/kernel/branches/net/applications/downloader/downloader.asm |
---|
0,0 → 1,1201 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2009-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; downloader.asm - HTTP client for KolibriOS ;; |
;; ;; |
;; Based on HTTPC.asm for menuetos by ville turjanmaa ;; |
;; ;; |
;; Programmers: Barsuk, Clevermouse, Marat Zakiyanov, ;; |
;; Kirill Lipatov, dunkaist, HidnPlayr ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
URLMAXLEN = 1024 |
primary_buffer_size = 4096 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; header |
dd 0x01 ; header version |
dd START ; entry point |
dd IM_END ; image size |
dd I_END ; required memory |
dd I_END ; esp |
dd params ; I_PARAM |
dd 0x0 ; I_Path |
include '../macros.inc' |
include '../proc32.inc' |
include '../network.inc' |
include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' |
include '../dll.inc' |
include '../debug-fdo.inc' |
START: |
mcall 68, 11 ; init heap so we can allocate memory dynamically |
mcall 40, EV_STACK |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; prepare webAddr area |
mov al, ' ' |
mov edi, webAddr |
mov ecx, URLMAXLEN |
rep stosb |
xor eax, eax |
stosb |
; prepare document area |
mov al, '/' |
mov edi, document |
stosb |
mov al, ' ' |
mov ecx, URLMAXLEN-1 |
rep stosb |
call load_settings |
cmp byte[params], 0 |
je prepare_event ;red |
; we have an url |
mov edi, document_user |
mov al, ' ' |
mov ecx, URLMAXLEN |
rep stosb |
mov esi, params |
mov edi, document_user |
; copy untill space or 0 |
.copy_param: |
mov al, [esi] |
test al, al |
jz .done |
cmp al, ' ' |
jz .done_inc |
mov [edi], al |
inc esi |
inc edi |
jmp .copy_param |
.done_inc: |
; url is followed by shared memory name. |
inc esi |
.done: |
mov [shared_name], esi |
mov ah, 22 ; strange way to tell that socket should be opened... |
call socket_commands |
jmp still |
prepare_event: |
; Report events |
; Stack 8 + defaults |
mcall 40, 10100111b |
red: ; redraw |
call draw_window |
still: |
mcall 23, 1 ; wait here for event |
cmp eax, 1 ; redraw request ? |
je red |
cmp eax, 2 ; key in buffer ? |
je key |
cmp eax, 3 ; button in buffer ? |
je button |
cmp eax, 6 ; mouse in buffer ? |
je mouse |
; Get the web page data from the remote server |
cmp eax, 8 |
jne still |
call read_incoming_data |
cmp [status], 4 |
je .no_send |
mov [onoff], 1 |
call send_request |
.no_send: |
call print_status |
cmp [prev_status], 4 |
jne no_close |
cmp [status], 4 ; connection closed by server |
jbe no_close ; respond to connection close command |
; draw page |
call read_incoming_data |
mcall close, [socketnum] |
mov [onoff], 0 |
no_close: |
jmp still |
key: |
mcall 2 ; read key |
stdcall [edit_box_key], dword edit1 |
shr eax, 8 |
cmp eax, 13 |
je retkey |
jmp still |
button: |
mcall 17 ; get id |
cmp ah, 26 |
je save |
cmp ah, 1 ; button id=1 ? |
jne noclose |
; DEBUGF 1, "Closing socket before exit...\n" |
close_end_exit: |
exit: |
or eax, -1 ; close this program |
mcall |
mouse: |
stdcall [edit_box_mouse], edit1 |
jmp still |
save: |
DEBUGF 1, "file saved\n" |
mcall 70, fileinfo |
mov ecx, [sc.work_text] |
or ecx, 0x80000000 |
mcall 4, <10, 93>, , download_complete |
jmp still |
noclose: |
cmp ah, 31 |
jne noup |
sub [display_from], 20 |
jmp still |
noup: |
cmp ah, 32 |
jne nourl |
add [display_from], 20 |
jmp still |
retkey: |
mov ah, 22 ; start load |
nourl: |
call socket_commands ; opens or closes the connection |
jmp still |
;**************************************************************************** |
; Function |
; send_request |
; |
; Description |
; Transmits the GET request to the server. |
; This is done as GET then URL then HTTP/1.1', 13, 10, 13, 10 in 3 packets |
; |
;**************************************************************************** |
send_request: |
pusha |
mov esi, string0 |
mov edi, request |
movsd |
; If proxy is used, make absolute URI - prepend http://<host> |
cmp byte[proxyAddr], 0 |
jz .noproxy |
mov dword[edi], 'http' |
mov byte[edi+4], ':' |
mov word[edi+5], '//' |
add edi, 7 |
mov esi, webAddr |
.copy_host_loop: |
lodsb |
cmp al, ' ' |
jz .noproxy |
stosb |
jmp .copy_host_loop |
.noproxy: |
xor edx, edx ; 0 |
.next_edx: |
; Determine the length of the url to send in the GET request |
mov al, [edx+document] |
cmp al, ' ' |
je .document_done |
mov [edi], al |
inc edi |
inc edx |
jmp .next_edx |
.document_done: |
mov esi, stringh |
mov ecx, stringh_end-stringh |
rep movsb |
xor edx, edx ; 0 |
.webaddr_next: |
mov al, [webAddr + edx] |
cmp al, ' ' |
je .webaddr_done |
mov [edi], al |
inc edi |
inc edx |
jmp .webaddr_next |
.webaddr_done: |
cmp byte[proxyUser], 0 |
jz @f |
call append_proxy_auth_header |
@@: |
mov esi, connclose |
mov ecx, connclose_end-connclose |
rep movsb |
pusha |
mov eax, 63 |
mov ebx, 1 |
mov edx, request |
@@: |
mov cl, [edx] |
cmp edx, edi |
jz @f |
mcall |
inc edx |
jmp @b |
@@: |
popa |
mov esi, edi |
sub esi, request ; length |
xor edi, edi ; flags |
;;;;now write \r\nConnection: Close \r\n\r\n |
mcall send, [socketnum], request ;' HTTP/1.1 .. ' |
popa |
ret |
;**************************************************************************** |
; Function |
; print_status |
; |
; Description |
; displays the socket/data received status information |
; |
;**************************************************************************** |
print_status: |
pusha |
mcall 26, 9 |
cmp eax, [nextupdate] |
jb status_return |
add eax, 25 |
mov [nextupdate], eax |
mov ecx, [winys] |
shl ecx, 16 |
add ecx, -18 shl 16 + 10 |
mcall 13, <5, 100>, , 0xffffff |
mov edx, 12 shl 16 - 18 |
add edx, [winys] |
xor esi, esi |
mcall 47, <3, 0>, [status], , |
mov edx, 40 shl 16 - 18 |
add edx, [winys] |
mcall , <6, 0>, [pos] |
status_return: |
popa |
ret |
;**************************************************************************** |
; Function |
; read_incoming_data |
; |
; Description |
; receive the web page from the server, storing it without processing |
; |
;**************************************************************************** |
read_incoming_data: |
cmp [onoff], 1 |
je .rid |
ret |
.rid: |
push esi |
push edi |
DEBUGF 1, "rid\n" |
.read: |
mcall recv, [socketnum], primary_buf, primary_buffer_size, 0 |
inc eax ; -1 = error (socket closed?) |
jz .no_more_data |
dec eax ; 0 bytes... |
jz .read |
mov edi, [pos] |
add [pos], eax |
push eax |
mcall 68, 20, [pos], [buf_ptr] |
mov [buf_ptr], eax |
add edi, eax |
mov esi, primary_buf |
pop ecx ; number of recently read bytes |
lea edx, [ecx - 3] |
rep movsb |
.no_more_data: |
; mov [status], 4 ; connection closed by server |
call parse_result |
mov ecx, [shared_name] |
test ecx, ecx |
jz @f |
cmp [ecx], byte 0 |
jnz save_in_shared |
@@: |
mcall 70, fileinfo |
mov ecx, [sc.work_text] |
or ecx, 0x80000000 |
mcall 4, <10, 93>, , download_complete |
DEBUGF 1, "file saved\n" |
pop edi |
pop esi |
; if called from command line, then exit |
cmp byte[params], 0 |
jne exit |
ret |
save_in_shared: |
mov esi, 1 ; SHM_OPEN+SHM_WRITE |
mcall 68, 22 |
test eax, eax |
jz save_in_shared_done |
sub edx, 4 |
jbe save_in_shared_done |
mov ecx, [final_size] |
cmp ecx, edx |
jb @f |
mov ecx, edx |
@@: |
mov [eax], ecx |
lea edi, [eax+4] |
mov esi, [final_buffer] |
mov edx, ecx |
shr ecx, 2 |
rep movsd |
mov ecx, edx |
and ecx, 3 |
rep movsb |
save_in_shared_done: |
pop edi |
pop esi |
jmp exit |
; this function cuts header, and removes chunk sizes if doc is chunked |
; in: buf_ptr, pos; out: buf_ptr, pos. |
parse_result: |
; close socket |
mcall close, [socketnum] |
DEBUGF 1, "close socketnum: 0x%x\n", eax |
mov edi, [buf_ptr] |
mov edx, [pos] |
mov [buf_size], edx |
; mcall 70, fileinfo_tmp |
DEBUGF 1, "pos = 0x%x\n", edx |
; first, find end of headers |
.next_byte: |
cmp dword[edi], 0x0d0a0d0a ; ìíå ëåíü ÷èòàòü ñòàíäàðò, ïóñòü áóäóò îáà âàðèàíòà |
je .end_of_headers |
cmp dword[edi], 0x0a0d0a0d |
je .end_of_headers |
inc edi |
dec edx |
jne .next_byte |
; no end of headers. it's an error. let client see all those headers. |
ret |
.end_of_headers: |
; here we look at headers and search content-length or transfer-encoding headers |
; DEBUGF 1, "eoh\n" |
sub edi, [buf_ptr] |
add edi, 4 |
mov [body_pos], edi ; store position where document body starts |
mov [is_chunked], 0 |
; find content-length in headers |
; not good method, but should work for 'Content-Length:' |
mov esi, [buf_ptr] |
mov edi, s_contentlength |
mov ebx, [body_pos] |
xor edx, edx ; 0 |
.cl_next: |
mov al, [esi] |
cmp al, [edi + edx] |
jne .cl_fail |
inc edx |
cmp edx, len_contentlength |
je .cl_found |
jmp .cl_incr |
.cl_fail: |
xor edx, edx ; 0 |
.cl_incr: |
inc esi |
dec ebx |
je .cl_error |
jmp .cl_next |
.cl_error: |
; DEBUGF 1, "content-length not found\n" |
; find 'chunked' |
; äà, ÿ êîïèðóþ êîä, ýòî óæàñíî, íî ìíå õî÷åòñÿ, ÷òîáû ïîñêîðåå çàðàáîòàëî |
; à òàì óæ îòðåôàêòîðþ |
mov esi, [buf_ptr] |
mov edi, s_chunked |
mov ebx, [body_pos] |
xor edx, edx ; 0 |
.ch_next: |
mov al, [esi] |
cmp al, [edi + edx] |
jne .ch_fail |
inc edx |
cmp edx, len_chunked |
je .ch_found |
jmp .ch_incr |
.ch_fail: |
xor edx, edx ; 0 |
.ch_incr: |
inc esi |
dec ebx |
je .ch_error |
jmp .ch_next |
.ch_error: |
; if neither of the 2 headers is found, it's an error |
; DEBUGF 1, "transfer-encoding: chunked not found\n" |
mov eax, [pos] |
sub eax, [body_pos] |
jmp .write_final_size |
.ch_found: |
mov [is_chunked], 1 |
mov eax, [body_pos] |
add eax, [buf_ptr] |
sub eax, 2 |
mov [prev_chunk_end], eax |
jmp parse_chunks |
.cl_found: |
call read_number ; eax = number from *esi |
.write_final_size: |
mov [final_size], eax ; if this works, i will b very happy... |
mov ebx, [pos] ; we well check if it is right |
sub ebx, [body_pos] |
; everything is ok, so we return |
mov eax, [body_pos] |
mov ebx, [buf_ptr] |
add ebx, eax |
mov [final_buffer], ebx |
; mov ebx, [pos] |
; sub ebx, eax |
; mov [final_size], ebx |
ret |
parse_chunks: |
; DEBUGF 1, "parse chunks\n" |
; we have to look through the data and remove sizes of chunks we see |
; 1. read size of next chunk |
; 2. if 0, it's end. if not, continue. |
; 3. make a good buffer and copy a chunk there |
xor eax, eax |
mov [final_buffer], eax ; 0 |
mov [final_size], eax ; 0 |
.read_size: |
mov eax, [prev_chunk_end] |
mov ebx, eax |
sub ebx, [buf_ptr] |
mov edx, eax |
; DEBUGF 1, "rs " |
cmp ebx, [pos] |
jae chunks_end ; not good |
call read_hex ; in: eax=pointer to text. out:eax=hex number, ebx=end of text. |
cmp eax, 0 |
jz chunks_end |
add ebx, 1 |
mov edx, ebx ; edx = size of size of chunk |
add ebx, eax |
mov [prev_chunk_end], ebx |
; DEBUGF 1, "sz " |
; do copying: from buf_ptr+edx to final_buffer+prev_final_size count eax |
; realloc final buffer |
push eax |
push edx |
push dword [final_size] |
add [final_size], eax |
mcall 68, 20, [final_size], [final_buffer] |
mov [final_buffer], eax |
; DEBUGF 1, "re " |
pop edi |
pop esi |
pop ecx |
; add [pos], ecx |
add edi, [final_buffer] |
; DEBUGF 1, "cp " |
rep movsb |
jmp .read_size |
chunks_end: |
; free old buffer |
DEBUGF 1, "chunks end\n" |
mcall 68, 13, [buf_ptr] |
; done! |
ret |
; reads content-length from [edi+ecx], result in eax |
read_number: |
push ebx |
xor eax, eax |
xor ebx, ebx |
.next: |
mov bl, [esi] |
cmp bl, '0' |
jb .not_number |
cmp bl, '9' |
ja .not_number |
sub bl, '0' |
shl eax, 1 |
lea eax, [eax + eax * 4] ; eax *= 10 |
add eax, ebx |
.not_number: |
cmp bl, 13 |
je .done |
inc esi |
jmp .next |
.done: |
pop ebx |
ret |
; reads hex from eax, result in eax, end of text in ebx |
read_hex: |
add eax, 2 |
mov ebx, eax |
mov eax, [ebx] |
mov [deba], eax |
xor eax, eax |
xor ecx, ecx |
.next: |
mov cl, [ebx] |
inc ebx |
cmp cl, 0x0d |
jz .done |
or cl, 0x20 |
sub cl, '0' |
jb .bad |
cmp cl, 0x9 |
jbe .adding |
sub cl, 'a'-'0'-10 |
cmp cl, 0x0a |
jb .bad |
cmp cl, 0x0f |
ja .bad |
.adding: |
shl eax, 4 |
or eax, ecx |
; jmp .not_number |
;.bad: |
.bad: |
jmp .next |
.done: |
ret |
;**************************************************************************** |
; Function |
; socket_commands |
; |
; Description |
; opens or closes the socket |
; |
;**************************************************************************** |
socket_commands: |
cmp ah, 22 ; open socket |
jne tst3 |
DEBUGF 1, "opening socket\n" |
; Clear all page memory |
xor eax, eax |
mov [prev_chunk_end], eax ; 0 |
cmp [buf_ptr], eax ; 0 |
jz no_free |
mcall 68, 13, [buf_ptr] ; free buffer |
no_free: |
xor eax, eax |
mov [buf_size], eax ; 0 |
; Parse the entered url |
call parse_url |
mov edx, 80 |
cmp byte [proxyAddr], 0 |
jz @f |
mov eax, [proxyPort] |
xchg al, ah |
mov [server_port], ax |
@@: |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
mov [pagexs], 80 |
push eax |
xor eax, eax ; 0 |
mov [pos], eax |
mov [pagex], eax |
mov [pagey], eax |
mov [command_on_off], eax |
mov [is_body], eax |
pop eax |
ret |
tst3: |
cmp ah, 24 ; close socket |
jne no_24 |
mcall close, [socketnum] |
no_24: |
ret |
;**************************************************************************** |
; Function |
; parse_url |
; |
; Description |
; parses the full url typed in by the user into a web address ( that |
; can be turned into an IP address by DNS ) and the page to display |
; DNS will be used to translate the web address into an IP address, if |
; needed. |
; url is at document_user and will be space terminated. |
; web address goes to webAddr and is space terminated. |
; ip address goes to server_ip |
; page goes to document and is space terminated. |
; |
; Supported formats: |
; <protocol://>address<page> |
; <protocol> is optional, removed and ignored - only http supported |
; <address> is required. It can be an ip address or web address |
; <page> is optional and must start with a leading / character |
; |
;**************************************************************************** |
parse_url: |
; First, reset destination variables |
mov al, ' ' |
mov edi, document |
mov ecx, URLMAXLEN |
rep stosb |
mov edi, webAddr |
mov ecx, URLMAXLEN |
rep stosb |
mov al, '/' |
mov [document], al |
mov esi, document_user |
; remove any leading protocol text |
mov ecx, URLMAXLEN |
mov ax, '//' |
pu_000: |
cmp [esi], byte ' ' ; end of text? |
je pu_002 ; yep, so not found |
cmp [esi], ax |
je pu_001 ; Found it, so esi+2 is start |
inc esi |
loop pu_000 |
pu_002: |
; not found, so reset esi to start |
mov esi, document_user-2 |
pu_001: |
add esi, 2 |
mov ebx, esi ; save address of start of web address |
mov edi, document_user + URLMAXLEN ; end of string |
; look for page delimiter - it's a '/' character |
pu_003: |
cmp [esi], byte ' ' ; end of text? |
je pu_004 ; yep, so none found |
cmp esi, edi ; end of string? |
je pu_004 ; yep, so none found |
cmp [esi], byte '/' ; delimiter? |
je pu_005 ; yep - process it |
inc esi |
jmp pu_003 |
pu_005: |
; copy page to document address |
; esi = delimiter |
push esi |
mov ecx, edi ; end of document_user |
mov edi, document |
pu_006: |
movsb |
cmp esi, ecx |
je pu_007 ; end of string? |
cmp [esi], byte ' ' ; end of text |
; je pu_007 ; äçåí-àññåìáëåð |
; jmp pu_006 ; íå íàäî ïëîäèòü ñóùíîñòè ïî íàïðàñíó |
jne pu_006 |
pu_007: |
pop esi ; point esi to '/' delimiter |
pu_004: |
; copy web address to webAddr |
; start in ebx, end in esi-1 |
mov ecx, esi |
mov esi, ebx |
mov edi, webAddr |
pu_008: |
movsb |
cmp esi, ecx |
; je pu_009 ; äçåí-àññåìáëåð |
; jmp pu_008 ; íå íàäî ïëîäèòü ñóùíîñòè ïî íàïðàñíó |
jne pu_008 |
pu_009: |
; For debugging, display resulting strings |
DEBUGF 1, "%s", document_user |
DEBUGF 1, "%s", webAddr |
DEBUGF 1, "%s", document |
; Look up the ip address, or was it specified? |
mov al, [proxyAddr] |
cmp al, 0 |
jnz pu_015 |
mov al, [webAddr] |
pu_015: |
cmp al, '0' |
jb pu_010 ; Resolve address |
cmp al, '9' |
ja pu_010 ; Resolve address |
DEBUGF 1, "GotIP\n" |
; Convert address |
; If proxy is given, get proxy address instead of server |
mov esi, proxyAddr-1 |
cmp byte[esi+1], 0 |
jne pu_020 |
mov esi, webAddr-1 |
pu_020: |
mov edi, server_ip |
xor eax, eax |
ip1: |
inc esi |
cmp [esi], byte '0' |
jb ip2 |
cmp [esi], byte '9' |
ja ip2 |
imul eax, 10 |
movzx ebx, byte [esi] |
sub ebx, 48 |
add eax, ebx |
jmp ip1 |
ip2: |
mov [edi], al |
xor eax, eax |
inc edi |
cmp edi, server_ip+3 |
jbe ip1 |
jmp pu_011 |
pu_010: |
DEBUGF 1, "Resolving...\n" |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push webAddr |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
; jnz .fail_dns |
; fill in ip in sockstruct |
mov eax, [esi + addrinfo.ai_addr] |
mov eax, [eax + sockaddr_in.sin_addr] |
mov [server_ip], eax |
DEBUGF 1, "Resolved\n" |
pu_011: |
ret |
;*************************************************************************** |
; Function |
; load_settings |
; |
; Description |
; Load settings from configuration file network.ini |
; |
;*************************************************************************** |
load_settings: |
invoke ini.get_str, inifile, sec_proxy, key_proxy, proxyAddr, 256, proxyAddr |
invoke ini.get_int, inifile, sec_proxy, key_proxyport, 80 |
mov [proxyPort], eax |
invoke ini.get_str, inifile, sec_proxy, key_user, proxyUser, 256, proxyUser |
invoke ini.get_str, inifile, sec_proxy, key_password, proxyPassword, 256, proxyPassword |
ret |
;*************************************************************************** |
; Function |
; append_proxy_auth_header |
; |
; Description |
; Append header to HTTP request for proxy authentification |
; |
;*************************************************************************** |
append_proxy_auth_header: |
mov esi, proxy_auth_basic |
mov ecx, proxy_auth_basic_end - proxy_auth_basic |
rep movsb |
; base64-encode string <user>:<password> |
mov esi, proxyUser |
apah000: |
lodsb |
test al, al |
jz apah001 |
call encode_base64_byte |
jmp apah000 |
apah001: |
mov al, ':' |
call encode_base64_byte |
mov esi, proxyPassword |
apah002: |
lodsb |
test al, al |
jz apah003 |
call encode_base64_byte |
jmp apah002 |
apah003: |
call encode_base64_final |
ret |
encode_base64_byte: |
inc ecx |
shl edx, 8 |
mov dl, al |
cmp ecx, 3 |
je ebb001 |
ret |
ebb001: |
shl edx, 8 |
inc ecx |
ebb002: |
rol edx, 6 |
xor eax, eax |
xchg al, dl |
mov al, [base64_table+eax] |
stosb |
loop ebb002 |
ret |
encode_base64_final: |
mov al, 0 |
test ecx, ecx |
jz ebf000 |
call encode_base64_byte |
test ecx, ecx |
jz ebf001 |
call encode_base64_byte |
mov byte [edi-2], '=' |
ebf001: |
mov byte [edi-1], '=' |
ebf000: |
ret |
; ********************************************* |
; ******* WINDOW DEFINITIONS AND DRAW ******** |
; ********************************************* |
draw_window: |
mcall 12, 1 |
mcall 48, 3, sc, 40 ;get system colors |
mov edx, [sc.work] |
or edx, 0x34000000 |
mcall 0, <50, 370>, <350, 140>, , 0, title ;draw window |
mov ecx, [sc.work_text] |
or ecx, 80000000h |
mcall 4, <14, 14>, , type_pls ;"URL:" |
edit_boxes_set_sys_color edit1, editboxes_end, sc |
stdcall [edit_box_draw], edit1 |
; RELOAD |
mcall 8, <90, 68>, <54, 16>, 22, [sc.work_button] |
; STOP |
mcall , <166, 50>, <54, 16>, 24 |
; SAVE |
mcall , <224, 54>, , 26 |
; BUTTON TEXT |
mov ecx, [sc.work_button_text] |
or ecx, 80000000h |
mcall 4, <102, 59>, , button_text |
mcall 12, 2 ; end window redraw |
ret |
;----------------------------------------------------------------------------- |
; Data area |
;----------------------------------------------------------------------------- |
align 4 |
@IMPORT: |
library libini, 'libini.obj', \ |
box_lib, 'box_lib.obj', \ |
network, 'network.obj' |
import libini, \ |
ini.get_str, 'ini_get_str', \ |
ini.get_int, 'ini_get_int' |
import box_lib, \ |
edit_box_draw, 'edit_box', \ |
edit_box_key, 'edit_box_key', \ |
edit_box_mouse, 'edit_box_mouse' |
import network,\ |
getaddrinfo, 'getaddrinfo',\ |
freeaddrinfo, 'freeaddrinfo',\ |
inet_ntoa, 'inet_ntoa' |
;--------------------------------------------------------------------- |
fileinfo dd 2, 0, 0 |
final_size dd 0 |
final_buffer dd 0 |
db '/rd/1/.download', 0 |
body_pos dd 0 |
buf_size dd 0 |
buf_ptr dd 0 |
deba dd 0 |
db 0 |
;--------------------------------------------------------------------- |
mouse_dd dd 0 |
edit1 edit_box 295, 48, 10, 0xffffff, 0xff, 0x80ff, 0, 0x8000, URLMAXLEN, document_user, mouse_dd, ed_focus+ed_always_focus, 7, 7 |
editboxes_end: |
;--------------------------------------------------------------------- |
include_debug_strings |
;--------------------------------------------------------------------- |
type_pls db 'URL:', 0 |
button_text db 'DOWNLOAD STOP RESAVE', 0 |
download_complete db 'File saved as /rd/1/.download', 0 |
display_from dd 20 |
pos dd 0 |
pagex dd 0 |
pagey dd 0 |
pagexs dd 80 |
command_on_off dd 0 |
text_type db 1 |
com2 dd 0 |
script dd 0 |
socketnum dd 0 |
addr dd 0 |
ya dd 0 |
len dd 0 |
title db 'HTTP Downloader', 0 |
;--------------------------------------------------------------------- |
s_contentlength db 'Content-Length:' |
len_contentlength = 15 |
s_chunked db 'Transfer-Encoding: chunked' |
len_chunked = $ - s_chunked |
is_body dd 0 ; 0 if headers, 1 if content |
is_chunked dd 0 |
prev_chunk_end dd 0 |
cur_chunk_size dd 0 |
string0: db 'GET ' |
stringh db ' HTTP/1.1', 13, 10, 'Host: ' |
stringh_end: |
proxy_auth_basic db 13, 10, 'Proxy-Authorization: Basic ' |
proxy_auth_basic_end: |
connclose db 13, 10, 'User-Agent: Kolibrios Downloader', 13, 10, 'Connection: Close', 13, 10, 13, 10 |
connclose_end: |
base64_table db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' |
db '0123456789+/' |
inifile db '/sys/network.ini', 0 |
sec_proxy: |
key_proxy db 'proxy', 0 |
key_proxyport db 'port', 0 |
key_user db 'user', 0 |
key_password db 'password', 0 |
sockaddr1: |
dw AF_INET4 |
server_port dw 0x5000 ; 80 |
server_ip dd 0 |
rb 10 |
proxyPort dd 80 |
shared_name dd 0 |
status dd 0x0 |
prev_status dd 0x0 |
onoff dd 0x0 |
nextupdate dd 0 |
winys dd 400 |
;--------------------------------------------------------------------- |
document_user db 'http://', 0 |
;--------------------------------------------------------------------- |
IM_END: |
;--------------------------------------------------------------------- |
rb URLMAXLEN-(IM_END - document_user) |
;--------------------------------------------------------------------- |
sc system_colors |
;--------------------------------------------------------------------- |
align 4 |
document rb URLMAXLEN |
;--------------------------------------------------------------------- |
align 4 |
webAddr rb URLMAXLEN+1 |
;--------------------------------------------------------------------- |
align 4 |
primary_buf rb primary_buffer_size |
params rb 1024 |
request rb 256 |
proxyAddr rb 256 |
proxyUser rb 256 |
proxyPassword rb 256 |
rb 4096 ; stack |
I_END: |
/kernel/branches/net/applications/ftpc/ftpc.asm |
---|
0,0 → 1,390 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ftpc.asm - FTP client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
__DEBUG__ = 0 |
__DEBUG_LEVEL__ = 1 |
BUFFERSIZE = 1024 |
STATUS_CONNECTING = 0 |
STATUS_CONNECTED = 1 |
STATUS_NEEDPASSWORD = 1 |
STATUS_LOGGED_IN = 3 |
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem+0x1000 ; required memory |
dd mem+0x1000 ; stack pointer |
dd s ; parameters |
dd 0 ; path |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../debug-fdo.inc' |
include '../network.inc' |
include 'usercommands.inc' |
include 'servercommands.inc' |
; entry point |
start: |
DEBUGF 1, "hello" |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
; Check for parameters |
cmp byte [s], 0 |
jne resolve |
main: |
call [con_cls] |
; Welcome user |
push str1 |
call [con_write_asciiz] |
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
; check for exit |
test eax, eax |
jz done |
cmp byte [esi], 10 |
jz done |
resolve: |
; delete terminating '\n' |
mov esi, s |
@@: |
lodsb |
cmp al, 0x20 |
ja @r |
mov byte [esi-1], 0 |
; call [con_cls] |
push str3 |
call [con_write_asciiz] |
push s |
call [con_write_asciiz] |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push s ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz fail |
; write results |
push str8 |
call [con_write_asciiz] |
; mov edi, esi |
; convert IP address to decimal notation |
mov eax, [esi+addrinfo.ai_addr] |
mov eax, [eax+sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
push eax |
call [inet_ntoa] |
; write result |
push eax |
call [con_write_asciiz] |
; free allocated memory |
push esi |
call [freeaddrinfo] |
push str9 |
call [con_write_asciiz] |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
jz fail2 |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
mcall 40, 1 shl 7 |
mov [status], STATUS_CONNECTING |
mov [offset], buffer_ptr |
wait_for_serverdata: |
mcall 10 |
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz exit |
; receive socket data |
mcall recv, [socketnum], [offset], BUFFERSIZE, 0 |
inc eax |
jz wait_for_serverdata |
dec eax |
jz wait_for_serverdata |
; extract commands, copy them to "s" buffer |
add eax, buffer_ptr ; eax = end pointer |
mov esi, buffer_ptr ; esi = current pointer |
.nextcommand: |
mov edi, s |
.byteloop: |
cmp esi, eax |
jae wait_for_serverdata |
lodsb |
cmp al, 10 ; excellent, we might have a command |
je .got_command |
cmp al, 13 ; just ignore this crap |
je .byteloop |
stosb |
jmp .byteloop |
; we have a newline check if its a command |
.got_command: |
xor al, al |
stosb |
; push esi eax |
; print it to the screen |
pushd s |
call [con_write_asciiz] |
pushd str4 ; newline |
call [con_write_asciiz] |
; cmp byte[s+2], " " |
; jne .not_command |
lea ecx, [edi - s] |
call server_parser |
; .not_command: |
; pop eax esi |
; jmp .nextcommand |
wait_for_usercommand: |
cmp [status], STATUS_CONNECTED |
je .connected |
cmp [status], STATUS_NEEDPASSWORD |
je .needpass |
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz exit |
cmp dword[s], "list" |
je cmd_list |
cmp dword[s], "help" |
je cmd_help |
push str_unkown |
call [con_write_asciiz] |
jmp wait_for_usercommand |
.connected: |
push str_user |
call [con_write_asciiz] |
mov dword[s], "USER" |
mov byte[s+4], " " |
jmp .send |
.needpass: |
push str_pass |
call [con_write_asciiz] |
mov dword[s], "PASS" |
mov byte[s+4], " " |
.send: |
; read string |
mov esi, s+5 |
push 256 |
push esi |
call [con_gets] |
mov edi, s+5 |
mov ecx, 256 |
xor al, al |
repne scasb |
lea esi, [edi-s-1] |
mcall send, [socketnum], s |
jmp wait_for_usercommand |
open_dataconnection: |
cmp [status], STATUS_LOGGED_IN |
jne .fail |
mov dword[s], "PASV" |
mov byte[s+4], 10 |
mcall send, [socketnum], s, 5 |
ret |
.fail: |
push str6 |
call [con_write_asciiz] |
ret |
fail2: |
push str6 |
call [con_write_asciiz] |
jmp fail.wait |
fail: |
push str5 |
call [con_write_asciiz] |
.wait: |
push str10 |
call [con_write_asciiz] |
call [con_getch2] |
jmp main |
done: |
push 1 |
call [con_exit] |
exit: |
mcall close, [socketnum] |
mcall -1 |
; data |
title db 'FTP client',0 |
str1 db 'FTP client for KolibriOS v0.01',10,10,'Please enter ftp server address.',10,0 |
str2 db '> ',0 |
str3 db 'Connecting to ',0 |
str4 db 10,0 |
str5 db 10,'Name resolution failed.',10,0 |
str6 db 10,'Socket error.',10,0 |
str8 db ' (',0 |
str9 db ')',10,0 |
str10 db 'Push any key to continue.',0 |
str_user db "username: ",0 |
str_pass db "password: ",0 |
str_unkown db "unkown command",10,0 |
str_help db "available commands:",10,10 |
db "help list",10,0 |
str_open db "opening data socket",10,0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0x1500 ; 21 |
.ip dd 0 |
rb 10 |
sockaddr2: |
dw AF_INET4 |
.port dw 0 |
.ip dd 0 |
rb 10 |
include_debug_strings ; ALWAYS present in data section |
; import |
align 4 |
@IMPORT: |
library network, 'network.obj', console, 'console.obj' |
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz,'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos',\ |
con_write_string, 'con_write_string',\ |
con_get_flags, 'con_get_flags' |
i_end: |
active_passive db ? |
socketnum dd ? |
datasocket dd ? |
buffer_ptr rb 2*BUFFERSIZE |
status db ? |
offset dd ? |
s rb 1024 |
mem: |
/kernel/branches/net/applications/ftpc/servercommands.inc |
---|
0,0 → 1,114 |
server_parser: |
; Commands are always 3 numbers and followed by a space |
; If a server decides it needs multiline output, |
; first lines will have a dash instead of space after numbers, |
; thus they are simply ignored. |
cmp dword[s], "150 " |
je data_ok |
cmp dword[s], "220 " |
je welcome |
cmp dword[s], "227 " |
je pasv_ok |
cmp dword[s], "230 " |
je login_ok |
cmp dword[s], "331 " |
je pass |
ret |
welcome: |
mov [status], STATUS_CONNECTED |
ret |
pass: |
mov [status], STATUS_NEEDPASSWORD |
ret |
login_ok: |
mov [status], STATUS_LOGGED_IN |
ret |
pasv_ok: |
sub ecx, 5 |
jb .fail |
mov al, "(" |
mov edi, s + 5 |
repne scasb |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je fail |
mov [datasocket], eax |
mov esi, edi |
call ascii_dec |
mov byte[sockaddr2.ip+0], bl |
call ascii_dec |
mov byte[sockaddr2.ip+1], bl |
call ascii_dec |
mov byte[sockaddr2.ip+2], bl |
call ascii_dec |
mov byte[sockaddr2.ip+3], bl |
call ascii_dec |
mov byte[sockaddr2.port+1], bl |
call ascii_dec |
mov byte[sockaddr2.port+0], bl |
push str_open |
call [con_write_asciiz] |
mcall connect, [datasocket], sockaddr2, 18 |
.fail: |
ret |
data_ok: |
mcall recv, [datasocket], buffer_ptr, BUFFERSIZE, 0 ; fixme: use other buffer |
inc eax |
jz .fail |
dec eax |
jz .fail |
mov byte[buffer_ptr + eax], 0 |
pushd buffer_ptr |
call [con_write_asciiz] |
.fail: |
ret |
ascii_dec: |
xor ebx, ebx |
mov cl, 3 |
.loop: |
lodsb |
sub al, '0' |
jb .done |
cmp al, 9 |
ja .done |
lea ebx, [ebx*4+ebx] |
shl ebx, 1 |
add bl, al |
dec cl |
jnz .loop |
.done: |
ret |
/kernel/branches/net/applications/ftpc/usercommands.inc |
---|
0,0 → 1,17 |
cmd_list: |
call open_dataconnection |
mov dword[s], "LIST" |
mov word[s+4], 0x0d0a |
mcall send, [socketnum], s, 6 |
jmp wait_for_serverdata |
cmd_help: |
push str_help |
call [con_write_asciiz] |
jmp wait_for_usercommand |
/kernel/branches/net/applications/ircc/window.inc |
---|
0,0 → 1,167 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
window_create: |
; allocate the window data block |
mcall 68, 12, sizeof.window_data |
test eax, eax |
jz .fail |
; fill it with all zeros |
push eax |
mov edi, eax |
mov ecx, (sizeof.window_data+3)/4 |
xor eax, eax |
rep stosd |
pop eax |
.fail: |
ret |
window_set_name: ; esi = ptr to name, ebx = window ptr |
pusha |
; Skip heading spaces |
.spaceloop: |
cmp byte[esi], ' ' |
jne .done |
inc esi |
jmp .spaceloop |
.done: |
; Now copy it |
lea edi, [ebx + window.name] |
mov ecx, MAX_WINDOWNAME_LEN |
.loop: |
lodsb |
cmp al, 0x21 |
jbe .addzero |
stosb |
dec ecx |
jnz .loop |
.addzero: |
xor al, al |
stosb |
call draw_windownames ; redraw it |
popa |
ret |
window_refresh: |
; set the correct buffer pointers ; FIXME: what is it good for? |
mov eax, [textbox_width] ; |
imul eax, 11 ; |
mov [pos], eax ; |
mov eax, [window_print] |
mov eax, [eax + window.data_ptr] |
add eax, window_data.text |
mov [text_start], eax |
ret |
window_updated: |
mov edi, [window_print] |
test [edi + window.flags], FLAG_UPDATED |
jnz .skip |
or [edi + window.flags], FLAG_UPDATED |
; now play a sound :) |
.skip: |
ret |
print_text: ; eax = start ptr |
; dl = end char |
pusha |
ptr2: |
mov bl, [eax] |
cmp bl, dl |
je ptr_ret |
cmp bl, 0 |
je ptr_ret |
call print_character |
inc eax |
jmp ptr2 |
ptr_ret: |
popa |
ret |
print_text2: ; esi = ptr to ASCIIZ string |
pusha |
.loop: |
lodsb |
test al, al |
jz .done |
mov bl, al |
call print_character |
jmp .loop |
.done: |
popa |
ret |
if TIMESTAMP |
print_timestamp: |
pusha |
mcall 3 ; get system time |
mov bl, '[' |
call print_character |
mov ecx, TIMESTAMP |
.loop: |
mov bl, al |
shr bl, 4 |
add bl, '0' |
call print_character |
mov bl, al |
and bl, 0x0f |
add bl, '0' |
call print_character |
dec ecx |
jz .done |
mov bl, ':' |
call print_character |
shr eax, 8 |
jmp .loop |
.done: |
mov bl, ']' |
call print_character |
mov bl, ' ' |
call print_character |
popa |
ret |
end if |
/kernel/branches/net/applications/ircc/gui.inc |
---|
0,0 → 1,316 |
draw_window: |
pusha |
mcall 9, thread_info, -1 ; get current window size |
mov eax, dword[thread_info+42] ; window xsize |
mov ebx, dword[thread_info+46] ; ysize |
mov edx, dword[thread_info+62] ; work area xsize |
mov esi, dword[thread_info+66] ; ysize |
sub eax, edx |
sub ebx, esi |
cmp edx, WIN_MIN_X |
jae .x_ok |
mov edx, WIN_MIN_X |
.x_ok: |
mov [xsize], edx |
add edx, eax |
cmp esi, WIN_MIN_Y |
jae .y_ok |
mov esi, WIN_MIN_Y |
.y_ok: |
mov [ysize], esi |
add esi, ebx |
mcall 67, -1, -1 ; set the new sizes |
mcall 12, 1 |
xor eax, eax ; draw window |
mov ebx, WIN_MIN_X |
mov ecx, WIN_MIN_Y |
mov edx, [colors.work] |
add edx, 0x33000000 |
mov edi, str_programname |
mcall |
mcall 12, 2 ;; when do we actually need this?? |
mov ebx, [xsize] |
mov ecx, [ysize] |
sub cx, 15 ;;;; |
push cx |
shl ecx, 16 |
pop cx |
mov edx, [colors.work_graph] |
mcall 38 ; draw line |
mov ecx, TOP_Y SHL 16 + TOP_Y |
mcall |
mov edi, [window_open] |
cmp [edi + window.type], WINDOWTYPE_CHANNEL |
jne .not_channel |
; draw a vertical separator line |
mov ebx, [xsize] |
sub ebx, USERLIST_X + SCROLLBAR_WIDTH + 3 |
push bx |
shl ebx, 16 |
pop bx |
mov ecx, [ysize] |
add ecx, TOP_Y SHL 16 -(15) ;;;; |
mcall |
call redraw_channel_list |
.not_channel: |
mov edx, [edi + window.data_ptr] |
add edx, window_data.text |
call draw_channel_text |
; editbox |
mov eax, [ysize] |
sub eax, 12 ;;;;;; |
mov [edit1.top], eax |
mov eax, [xsize] |
mov [edit1.width], eax |
push dword edit1 |
call [edit_box_draw] |
; tabs |
call draw_windownames |
popa |
ret |
redraw_channel_list: |
; First, calculate scrollbar |
mov ebx, [window_open] |
mov eax, [ebx + window.users] ; number of users in the open window |
mov [scroll1.max_area], eax |
mov eax, [ysize] |
sub eax, TOP_Y + 15 ;;;; |
push eax |
mov [scroll1.y_size], ax |
mov eax, [xsize] |
sub eax, SCROLLBAR_WIDTH |
mov [scroll1.x_pos], ax |
pop eax ; scrollbar height |
xor edx, edx |
mov ecx, 10 |
div ecx |
mov [scroll1.cur_area], eax |
; Do we need a scrollbar? |
cmp eax, [scroll1.max_area] |
jae .noscroll |
; Is the current position greater then the max position? |
cmp eax, [scroll1.position] |
ja @f |
mov [scroll1.position], eax |
@@: |
; OK, draw the scrollbar |
mov [scroll1.all_redraw], 1 |
push dword scroll1 |
call [scrollbar_v_draw] |
jmp print_channel_list |
.noscroll: |
mov [scroll1.position], 0 |
print_channel_list: |
pusha |
; Now, draw the usernames themselves |
; first, draw an invisible button |
mov ebx, [xsize] |
sub ebx, USERLIST_X + SCROLLBAR_WIDTH |
shl ebx, 16 |
push ebx |
mov bx, USERLIST_X |
mov ecx, [ysize] |
add ecx, TEXT_Y shl 16 - (TEXT_Y + 15) ;;;;; + 10??? |
push ecx ebx |
mov edx, 50 + 1 shl 29 + 1 shl 30 |
mcall 8 |
; now draw rectangle to clear the names |
pop ebx ecx |
mov edx, [colors.work] |
mcall 13 |
; now draw the names according with scrollbar position and window size |
mov eax, [scroll1.position] |
xor edx, edx |
mov ecx, MAX_NICK_LEN |
mul ecx |
mov edx, eax |
mov eax, [window_open] |
mov ebp, [eax + window.selected] |
add edx, [eax + window.data_ptr] |
sub ebp, [scroll1.position] |
add edx, window_data.names |
pop ebx |
mov bx, TEXT_Y |
mov ecx, [colors.work_text] |
or ecx, 0x80000000 ; ASCIIZ string |
mov eax, 4 ; draw text |
mov edi, [ysize] ; Calculate how many names will fit on screen |
sub edi, TEXT_Y + 15 ;+ 10 ;;;;; |
.loop: |
cmp byte[edx], 0 ; end of list? |
je .done |
dec ebp ; is this name selected? |
jnz .nothighlight |
; yes, highlight it |
pusha |
mov cx, bx |
mov bx, USERLIST_X |
shl ecx, 16 |
mov cx, 10 - 1 |
mov edx, 0x00000055 ; blue! |
mcall 13 |
popa |
mov ecx, 0x8000ffff ; cyan! |
mcall |
mov ecx, [colors.work_text] |
or ecx, 0x80000000 ; ASCIIZ string |
jmp .next |
.nothighlight: |
mcall |
.next: |
add edx, MAX_NICK_LEN ; next name |
add ebx, 10 ; height distance between lines |
sub edi, 10 |
ja .loop |
.done: |
popa |
ret |
draw_channel_text: |
pusha |
mov eax, 4 ; draw text |
mov ebx, TEXT_X shl 16 + TEXT_Y |
mov ecx, 12 ; 12 lines max ? |
mov esi, [textbox_width] |
.dct: |
pusha |
mov cx, bx |
shl ecx, 16 |
mov cx, 9 ; character height |
mov eax, 13 ; draw rectangle |
mov ebx, TEXT_X shl 16 |
mov bx, word[textbox_width] |
imul bx, 6 ; character width |
mov edx, [colors.work] |
mcall |
popa |
push ecx |
mov ecx, [colors.work_text] |
cmp word[edx], '* ' |
jne .no_red |
mov ecx, 0x00aa0000 |
jmp .draw |
.no_red: |
cmp word[edx], '**' |
jne .no_light_blue |
cmp byte[edx+2], '*' |
jne .no_light_blue |
mov ecx, 0x000000aa |
jmp .draw |
.no_light_blue: |
cmp byte[edx], '#' |
jne .no_blue |
mov ecx, 0x0000aa00 |
; jmp .draw |
.no_blue: |
.draw: |
mcall |
add edx, [textbox_width] |
add ebx, 10 ; height distance between lines |
pop ecx |
loop .dct |
popa |
ret |
draw_windownames: |
mov eax, 8 |
mov ebx, 5 shl 16 + 120 |
mov ecx, 12 shl 16 + 12 |
mov edx, WINDOW_BTN_START |
mov edi, windows |
.more_btn: |
mov esi, [colors.work_button] |
cmp [window_open], edi |
jne @f |
not esi |
and esi, 0x00ffffff |
@@: |
mcall |
inc edx |
add ebx, 125 shl 16 |
add edi, sizeof.window |
cmp [edi + window.data_ptr], 0 |
jne .more_btn |
mov eax, 4 |
mov ebx, 10 shl 16 + 15 |
mov ecx, [colors.work_button_text] |
or ecx, 0x80000000 ; ASCIIZ string |
lea edx, [windows + window.name] |
mov esi, MAX_WINDOWS |
.more: |
mcall |
add edx, sizeof.window |
cmp byte[edx], 0 |
je .enough |
add ebx, 125 shl 16 |
dec esi |
jnz .more |
.enough: |
ret |
/kernel/branches/net/applications/ircc/ircc.asm |
---|
0,0 → 1,476 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; IRC client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org, ;; |
;; text encoder/decoder by Clevermouse. ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
version equ '0.1' |
; connection status |
STATUS_DISCONNECTED = 0 |
STATUS_RESOLVING = 1 |
STATUS_CONNECTING = 2 |
STATUS_CONNECTED = 3 |
; window flags |
FLAG_UPDATED = 1 shl 0 |
FLAG_CLOSE = 1 shl 1 |
FLAG_RECEIVING_NAMES = 1 shl 2 |
; window types |
WINDOWTYPE_SERVER = 0 |
WINDOWTYPE_CHANNEL = 1 |
WINDOWTYPE_CHAT = 2 |
WINDOWTYPE_LIST = 3 |
WINDOWTYPE_DCC = 4 |
; supported encodings |
CP866 = 0 |
CP1251 = 1 |
UTF8 = 2 |
; settings |
USERCMD_MAX_SIZE = 400 |
WIN_MIN_X = 600 |
WIN_MIN_Y = 165 |
TEXT_X = 5 |
TEXT_Y = 30 |
TOP_Y = 25 |
MAX_WINDOWS = 20 |
MAX_USERS = 4096 |
MAX_NICK_LEN = 32 |
MAX_REAL_LEN = 32 ; realname |
MAX_SERVER_NAME = 256 |
MAX_CHANNEL_LEN = 40 |
MAX_CHANNELS = 37 |
MAX_COMMAND_LEN = 512 |
TIMESTAMP = 3 ; 3 = hh:mm:ss, 2 = hh:mm, 0 = no timestamp |
MAX_WINDOWNAME_LEN = 256 |
WINDOW_BTN_START = 100 |
SCROLLBAR_WIDTH = 12 |
USERLIST_X = 98 |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 1 ; header version |
dd START ; program start |
dd I_END ; program image size |
dd IM_END+2048 ; required amount of memory |
dd IM_END+2048 |
dd param |
dd path |
include "../macros.inc" |
include "../proc32.inc" |
include "../dll.inc" |
include "../network.inc" |
include "../struct.inc" |
include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' |
struct window |
data_ptr dd ? ; zero if not used |
flags db ? |
type db ? |
name rb MAX_WINDOWNAME_LEN |
users dd ? |
users_scroll dd ? |
selected dd ? ; selected user, 0 if none selected |
ends |
struct window_data |
text rb 120*60 |
title rb 256 |
names rb MAX_NICK_LEN * MAX_USERS |
usertext rb 256 |
usertextlen dd ? |
ends |
include "encodings.inc" |
include "window.inc" ; also contains text print routines |
include "serverparser.inc" |
include "userparser.inc" |
include "socket.inc" |
include "gui.inc" |
include "users.inc" |
START: |
mcall 68, 11 ; init heap so we can allocate memory dynamically |
; wanted events |
mcall 40, EVM_REDRAW + EVM_KEY + EVM_BUTTON + EVM_STACK + EVM_MOUSE |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; find path to main settings file (ircc.ini) |
mov edi, path ; Calculate the length of zero-terminated string |
xor al, al |
mov ecx, 1024 |
repne scasb |
dec edi |
mov eax, '.ini' |
stosd |
xor al, al |
stosb |
; Fill the window buffer with zeros |
mov edi, windows |
mov ecx, (sizeof.window*MAX_WINDOWS+3)/4 |
xor eax, eax |
rep stosd |
; clear command area too |
mov edi, servercommand |
mov ecx, 600/4 |
rep stosd |
; allocate window data block |
call window_create |
mov ebx, windows |
mov [ebx + window.data_ptr], eax |
mov [ebx + window.flags], 0 |
mov [ebx + window.type], WINDOWTYPE_SERVER |
add eax, window_data.text |
mov [text_start], eax |
call window_refresh |
; get system colors |
mcall 48, 3, colors, 40 |
; set edit box and scrollbar colors |
mov eax, [colors.work] |
mov [scroll1.bg_color], eax |
mov eax, [colors.work_button] |
mov [scroll1.front_color], eax |
mov eax, [colors.work_text] |
mov [scroll1.line_color], eax |
; get settings from ini |
invoke ini.get_str, path, str_user, str_nick, user_nick, MAX_NICK_LEN, default_nick |
invoke ini.get_str, path, str_user, str_real, user_real_name, MAX_REAL_LEN, default_real |
; Welcome user |
mov esi, str_welcome |
call print_text2 |
call draw_window ;;; FIXME (gui is not correctly drawn first time) |
redraw: |
call draw_window |
still: |
; wait here for event |
mcall 10 |
dec eax |
jz redraw |
dec eax |
jz main_window_key |
dec eax |
jz button |
cmp al, 3 |
je mouse |
call process_network_event |
mov edx, [window_open] |
test [edx + window.flags], FLAG_UPDATED |
jz .no_update |
and [edx + window.flags], not FLAG_UPDATED |
mov edx, [edx + window.data_ptr] |
add edx, window_data.text |
call draw_channel_text |
.no_update: |
call print_channel_list |
jmp still |
button: |
mcall 17 ; get id |
shr eax, 8 |
cmp ax, 1 ; close program |
je exit |
cmp ax, 50 |
jne @f |
mcall 37, 1 ; Get mouse position |
sub ax, TEXT_Y |
mov bl, 10 |
div bl |
and eax, 0x000000ff |
inc eax |
add eax, [scroll1.position] |
mov ebx, [window_open] |
mov [ebx + window.selected], eax |
call print_channel_list |
jmp still |
@@: |
sub ax, WINDOW_BTN_START |
jb exit |
cmp ax, MAX_WINDOWS |
ja exit |
mov dx, sizeof.window |
mul dx |
shl edx, 16 |
mov dx, ax |
add edx, windows |
cmp [edx + window.data_ptr], 0 |
je exit |
mov [window_open], edx |
call window_refresh |
call draw_window |
jmp still |
exit: |
mcall -1 |
main_window_key: |
mcall 2 |
push dword edit1 |
call [edit_box_key] |
cmp ah, 13 ; enter |
jne no_send2 |
call user_parser |
mov [edit1.size], 0 |
mov [edit1.pos], 0 |
push dword edit1 |
call [edit_box_draw] |
mov edx, [window_open] |
mov edx, [edx + window.data_ptr] |
add edx, window_data.text |
call draw_channel_text |
jmp still |
no_send2: |
jmp still |
mouse: |
push dword edit1 |
call [edit_box_mouse] |
; TODO: check if scrollbar is active |
push [scroll1.position] |
push dword scroll1 |
call [scrollbar_v_mouse] |
pop eax |
cmp eax, [scroll1.position] ; did the scrollbar move? |
je @f |
call print_channel_list |
@@: |
jmp still |
; DATA AREA |
encoding_text: |
db 'CP866 ' |
db 'CP1251' |
db 'UTF-8 ' |
encoding_text_len = 6 |
action_header db '*** ', 0 |
action_header_short db '* ', 0 |
ctcp_header db '-> [',0 |
ctcp_version db '] VERSION',10,0 |
ctcp_ping db '] PING',10,0 |
ctcp_time db '] TIME',10,0 |
has_left_channel db ' has left ', 0 |
joins_channel db ' has joined ', 0 |
is_now_known_as db ' is now known as ', 0 |
has_quit_irc db ' has quit IRC', 10, 0 |
sets_mode db ' sets mode ', 0 |
kicked db ' is kicked from ', 0 |
str_talking db 'Now talking in ',0 |
str_topic db 'Topic is ',0 |
str_setby db 'Set by ',0 |
str_version db 'VERSION ' |
str_programname db 'KolibriOS IRC client ', version, 0 |
str_user db 'user', 0 |
str_nick db 'nick', 0 |
str_real db 'realname', 0 |
str_email db 'email', 0 |
default_nick db 'kolibri_user', 0 |
default_real db 'Kolibri User', 0 |
str_welcome db 10 |
db ' ______________________ __ __ __',10 |
db '| \______ \_ ___ \ ____ | | |__| ____ _____/ |_',10 |
db '| || _/ \ \/ _/ ___\| | | |/ __ \ / \ __\',10 |
db '| || | \ \____ \ \___| |_| \ ___/| | \ |',10 |
db '|___||____|_ /\______ / \___ >____/__|\___ >___| /__|',10 |
db ' \/ \/ \/ \/ \/',10 |
db 10 |
db 'Welcome to IRC client ',version,' for KolibriOS',10 |
db 10 |
db 'Type /help for help',10,0 |
str_nickchange db 'Nickname is now ',0 |
str_realchange db 'Real name is now ',0 |
str_dotnewline db '.',10, 0 |
str_newline db 10, 0 |
str_connecting db 10,'* Connecting to ',0 |
str_help db 10,'following commands are available:',10 |
db 10 |
db '/nick <nick> : change nickname to <nick>',10 |
db '/real <real name> : change real name to <real name>',10 |
db '/server <address> : connect to server <address>',10 |
db '/code <code> : change codepage to cp866, cp1251, or utf8',10,0 |
str_1 db ' -',0 |
str_2 db '- ',0 |
str_sockerr db 'Socket Error',10,0 |
str_dnserr db 'Unable to resolve hostname.',10,0 |
str_refused db 'Connection refused',10,0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0x0b1a ; 6667 |
.ip dd 0 |
rb 10 |
status dd STATUS_DISCONNECTED |
text_start dd ? ; pointer to current textbox data |
irc_data dd 0x0 ; encoder |
textbox_width dd 80 ; in characters, not pixels ;) |
pos dd 66 * 11 ; encoder |
window_open dd windows |
window_print dd windows |
scroll dd 1 |
dd 12 |
align 4 |
@IMPORT: |
library network, 'network.obj',\ |
libini, 'libini.obj',\ |
boxlib, 'box_lib.obj' |
import network,\ |
getaddrinfo, 'getaddrinfo',\ |
freeaddrinfo, 'freeaddrinfo',\ |
inet_ntoa, 'inet_ntoa' |
import libini,\ |
ini.get_str, 'ini_get_str',\ |
ini.get_int, 'ini_get_int' |
import boxlib,\ |
edit_box_draw ,'edit_box' ,\ |
edit_box_key ,'edit_box_key' ,\ |
edit_box_mouse ,'edit_box_mouse' ,\ |
scrollbar_v_draw ,'scrollbar_v_draw' ,\ |
scrollbar_v_mouse,'scrollbar_v_mouse' |
usercommand db '/server chat.freenode.net', 0 |
rb MAX_COMMAND_LEN |
I_END: |
; width, left, top |
edit1 edit_box 0, 0, 0, 0xffffff, 0x6f9480, 0, 0, 0, USERCMD_MAX_SIZE, usercommand, mouse_dd, ed_focus, 25, 25 |
; xsize, xpos, ysize, ypos, max, cur, pos, bgcol, frcol, linecol |
scroll1 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1 |
scroll2 scrollbar SCROLLBAR_WIDTH, 300, 150, TOP_Y, 10, 100, 0, 0, 0, 0, 0, 1 |
main_PID dd ? ; identifier of main thread |
utf8_bytes_rest dd ? ; bytes rest in current UTF8 sequence |
utf8_char dd ? ; first bits of current UTF8 character |
gai_reqdata rb 32 ; buffer for getaddrinfo_start/process |
ip_list dd ? ; will be filled as pointer to addrinfo list |
packetbuf rb 1024 ; buffer for packets to server |
path rb 1024 |
param rb 1024 |
socketnum dd ? |
servercommand rb 600 |
thread_info rb 1024 |
xsize dd ? |
ysize dd ? |
colors system_colors |
irc_server_name rb MAX_SERVER_NAME |
user_nick rb MAX_NICK_LEN |
user_real_name rb MAX_REAL_LEN |
windows rb MAX_WINDOWS*sizeof.window |
mouse_dd dd ? |
IM_END: |
/kernel/branches/net/applications/ircc/serverparser.inc |
---|
0,0 → 1,928 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
server_parser: |
mov esi, servercommand |
cmp byte [esi], ':' |
jne .parse |
.spaceloop: |
lodsb |
test al, al |
jz .fail |
cmp al, ' ' |
jne .spaceloop |
.parse: |
mov eax, [esi] |
or eax, 0x20202020 |
mov edi, server_commands |
mov ecx, server_commands.number |
.loop: |
scasd |
je .got_cmd |
add edi, 4 |
dec ecx |
jnz .loop |
.fail: |
ret |
.got_cmd: |
jmp dword[edi] |
server_commands: |
dd '322 ', cmd_322 ; RPL_LIST |
dd '323 ', cmd_323 ; RPL_LISTEND |
dd '328 ', cmd_328 |
dd '332 ', cmd_topic |
dd '333 ', cmd_333 ; nickname and time of topic |
dd '353 ', cmd_353 ; name reply |
dd '366 ', cmd_366 ; end of names list |
dd '372 ', cmd_372 ; motd |
dd '375 ', cmd_375 ; start of motd |
dd '376 ', cmd_376 ; end of motd |
dd '421 ', cmd_421 ; unknown command |
dd 'join', cmd_join |
dd 'kick', cmd_kick |
dd 'mode', cmd_mode |
dd 'nick', cmd_nick |
dd 'part', cmd_part |
dd 'ping', cmd_ping |
dd 'priv', cmd_privmsg |
dd 'quit', cmd_quit |
dd 'noti', cmd_notice |
.number = ($ - server_commands) / 8 |
align 4 |
compare_to_nick: |
push esi |
mov ecx, MAX_NICK_LEN |
mov esi, user_nick |
.loop: |
lodsb |
cmp al, ' ' |
jbe .done |
cmp al, 'a' |
jb .ok |
cmp al, 'z' |
ja .ok |
sub al, 0x20 |
.ok: |
mov bl, byte[edi] |
cmp bl, 'a' |
jb .ok2 |
cmp bl, 'z' |
ja .ok2 |
sub bl, 0x20 |
.ok2: |
cmp bl, al |
jne .not_equal |
inc edi |
dec ecx |
jnz .loop |
.done: |
xor eax, eax |
pop esi |
ret |
.not_equal: |
or eax, -1 |
pop esi |
ret |
align 4 |
skip_nick: |
; First: skip the NICK (maybe we should verify it?) |
.nick: |
lodsb |
cmp al, ' ' |
je .skip |
cmp al, ':' |
je .skip |
jmp .nick |
; skip all leading spaces and semicolons |
.skip: |
lodsb |
cmp al, ' ' |
je .skip |
cmp al, ':' |
je .skip |
dec esi |
ret |
align 4 |
find_window: ; esi is ptr to windowname |
push esi |
mov edi, esi |
call compare_to_nick |
jne .nochat |
mov esi, servercommand+1 |
.nochat: |
; now search for window in list |
mov ebx, windows |
mov [window_print], ebx ; set first window (server window) as default output window |
.scanloop: |
cmp [ebx + window.data_ptr], 0 |
je .create_it |
push esi |
lea edi, [ebx + window.name] |
mov ecx, MAX_WINDOWNAME_LEN |
repe cmpsb |
pop esi |
cmp byte[edi-1], 0 |
je .got_it |
add ebx, sizeof.window |
; TODO: check buffer limits ? |
jmp .scanloop |
; create channel window - search for empty slot |
.create_it: |
mov ebx, windows |
mov ecx, MAX_WINDOWS |
.scanloop2: |
cmp [ebx + window.data_ptr], 0 |
je .free_found |
add ebx, sizeof.window |
dec ecx |
jnz .scanloop2 |
; Error: no more available windows! |
jmp .just_skip |
.free_found: |
push ebx |
call window_create |
pop ebx |
test eax, eax |
jz .just_skip |
mov [ebx + window.data_ptr], eax |
mov [ebx + window.type], WINDOWTYPE_CHAT |
mov [ebx + window.flags], 0 |
call window_set_name |
mov [window_open], ebx |
mov [window_print], ebx |
call window_refresh |
call draw_windownames |
jmp .just_skip |
; found it! |
.got_it: |
mov [window_print], ebx |
call window_refresh |
.just_skip: |
pop esi |
.skip1: |
; skip text |
lodsb |
test al, al |
jz .quit |
cmp al, ' ' |
jne .skip1 |
dec esi |
; now skip trailing spaces and semicolons |
.skip2: |
lodsb |
test al, al |
jz .quit |
cmp al, ' ' |
je .skip2 |
cmp al, ':' |
je .skip2 |
dec esi |
.quit: |
ret |
cmd_328: |
cmd_421: |
cmd_372: |
cmd_375: |
cmd_376: |
add esi, 4 |
jmp cmd_notice.loop |
cmd_notice: |
cmp byte[servercommand], ':' |
jne .gogogo |
mov byte [esi-1], 0 |
push esi |
mov esi, str_1 |
call print_text2 |
mov esi, servercommand+1 |
call print_text2 |
mov esi, str_2 |
call print_text2 |
pop esi |
.gogogo: |
add esi, 6 |
.loop: |
inc esi |
cmp byte [esi], 0 |
je .fail |
cmp byte [esi], ' ' |
jne .loop |
.loop2: |
inc esi |
cmp byte [esi], 0 |
je .fail |
cmp byte [esi], ' ' |
je .loop2 |
cmp byte [esi], ':' |
je .loop2 |
call print_text2 |
mov esi, str_newline |
call print_text2 |
.fail: |
ret |
cmd_ping: |
; Just change PING to PONG |
mov dword[esi], 'PONG' |
; Find the end of the command |
lea edi, [esi + 5] |
xor al, al |
repne scasb |
; Now send it back |
mov edx, esi |
mov esi, edi |
mov word [esi], 0x0d0a |
inc esi |
inc esi |
sub esi, edx |
mcall send, [socketnum], , , 0 |
ret |
cmd_privmsg: |
add esi, 8 ; skip 'PRIVMSG ' |
call find_window ; esi now points to end of destination name |
cmp byte[esi], 1 |
je cmd_ctcp |
cmp dword[esi], 'ACTI' ; Action? |
je .action |
; nope, just plain old privmsg |
if TIMESTAMP |
call print_timestamp |
end if |
push esi |
mov bl, '<' |
call print_character |
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
mov bl, '>' |
call print_character |
mov bl, ' ' |
call print_character |
pop esi |
call print_text2 |
mov bl, 10 |
call print_character |
.fail: |
ret |
.action: |
add esi, 8 |
push esi |
if TIMESTAMP |
call print_timestamp |
end if |
mov esi, action_header_short |
call print_text2 |
mov eax, servercommand+1 |
mov dl, ' ' |
call print_text |
mov bl, ' ' |
call print_character |
pop esi |
call print_text2 |
mov bl, 10 |
call print_character |
ret |
cmd_ctcp: |
inc esi |
cmp dword[esi], 'VERS' |
je .version |
cmp dword[esi], 'TIME' |
je .time |
cmp dword[esi], 'PING' |
je .ping |
ret |
.time: |
mov byte [esi+4], ' ' |
lea edi, [esi+5] |
; TODO: add system date (fn 29) in human readable format |
mcall 3 ; get system time |
mov ecx, 3 |
.timeloop: |
mov bl, al |
shr al, 4 |
add al, '0' |
stosb |
mov al, bl |
and al, 0x0f |
add al, '0' |
stosb |
dec ecx |
jz .timedone |
mov al, ':' |
stosb |
shr eax, 8 |
jmp .timeloop |
.timedone: |
xor al, al |
stosb |
call ctcp_reply |
if TIMESTAMP |
call print_timestamp |
end if |
mov esi, ctcp_header |
call print_text2 |
mov esi, servercommand+1 |
call print_text2 |
mov esi, ctcp_time |
call print_text2 |
ret |
.version: |
mov esi, str_version |
call ctcp_reply |
if TIMESTAMP |
call print_timestamp |
end if |
mov esi, ctcp_header |
call print_text2 |
mov esi, servercommand+1 |
call print_text2 |
mov esi, ctcp_version |
call print_text2 |
ret |
.ping: |
call ctcp_reply |
if TIMESTAMP |
call print_timestamp |
end if |
mov esi, ctcp_header |
call print_text2 |
mov esi, servercommand+1 |
call print_text2 |
mov esi, ctcp_ping |
call print_text2 |
ret |
ctcp_reply: |
push esi |
mov dword [usercommand], 'NOTI' |
mov dword [usercommand+4], 'CE ' |
mov esi, servercommand+1 |
mov edi, usercommand+7 |
.nickloop: |
lodsb |
cmp al, '!' |
je .done |
cmp al, ' ' |
je .done |
test al, al |
je .fail |
stosb |
jmp .nickloop |
.done: |
mov byte [esi-1], 0 |
mov ax, ' :' |
stosw |
mov al, 1 |
stosb |
pop esi |
.replyloop: |
lodsb |
cmp al, 1 |
jbe .done2 |
stosb |
jmp .replyloop |
.done2: |
mov al, 1 |
stosb |
mov ax, 0x0a0d |
stosw |
lea esi, [edi - usercommand] |
mcall send, [socketnum], usercommand, , 0 |
.fail: |
ret |
cmd_part: |
add esi, 5 ; skip 'PART ' |
push esi |
call skip_nick |
call find_window |
pop esi |
; Is it me who parted? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .dont_close |
; yes, close the window |
mov edi, [window_print] |
mov [edi + window.flags], FLAG_UPDATED + FLAG_CLOSE |
ret |
; somebody else parted, just print message |
.dont_close: |
push esi |
mov esi, action_header |
call print_text2 |
mov eax, servercommand+1 |
mov dl, '!' |
mov cl, ' ' |
call print_text |
mov esi, has_left_channel |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
ret |
cmd_join: |
add esi, 5 ; skip 'JOIN ' |
; compare nick: did we join a channel? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .no_new_window |
; create channel window - search for empty slot |
mov ebx, windows |
mov ecx, MAX_WINDOWS |
.loop: |
cmp [ebx + window.data_ptr], 0 |
je .free_found |
add ebx, sizeof.window |
dec ecx |
jnz .loop |
; Error: no more available windows!! ;;;;; TODO |
.fail: |
ret |
.free_found: |
push ebx |
call window_create |
pop ebx |
test eax, eax |
jz .fail |
mov [ebx + window.data_ptr], eax |
mov [ebx + window.type], WINDOWTYPE_CHANNEL |
mov [ebx + window.flags], 0 |
call window_set_name |
mov [window_open], ebx |
mov [window_print], ebx |
call window_refresh |
push esi |
mov esi, action_header |
call print_text2 |
mov esi, str_talking |
call print_text2 |
pop eax |
mov dl, ' ' |
call print_text |
mov esi, str_dotnewline |
call print_text2 |
call draw_window |
ret |
.no_new_window: |
push esi |
call find_window |
mov esi, action_header |
call print_text2 |
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
mov esi, joins_channel |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_add |
ret |
cmd_nick: |
; NOTE: This command applies to a user, and thus has no specific channel |
add esi, 5 ; skip 'NICK ' |
cmp byte[esi], ':' ; TODO: skip all spaces and semicolons? |
jne @f |
inc esi |
@@: |
; Change the nick in the current userlist. TODO: check other channels too! |
push esi |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
mov esi, [esp] |
call user_add |
call redraw_channel_list |
; Is it me who changed nick? |
mov edi, servercommand+1 |
call compare_to_nick |
pop esi |
jne .not_me |
mov ecx, MAX_NICK_LEN-1 |
push esi |
.copyloop: |
lodsb |
test al, al |
jz .copydone |
cmp al, ' ' |
je .copydone |
stosb |
dec ecx |
jnz .copyloop |
.copydone: |
xor al, al |
stosb |
pop esi |
.not_me: |
; Now print a message on the current channel |
push esi |
mov esi, action_header_short |
call print_text2 |
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
mov esi, is_now_known_as |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
ret |
cmd_kick: |
add esi, 5 ; skip 'KICK ' |
; Is it me who got kicked? |
mov edi, servercommand+1 |
call compare_to_nick |
jne .not_me |
; TODO: mark channel as disconnected |
.not_me: |
; find the channel user has been kicked from |
push esi |
call skip_nick |
call find_window |
mov esi, action_header_short |
call print_text2 |
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
mov esi, kicked |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
ret |
cmd_quit: |
; NOTE: This command applies to a user, and thus has no specific channel |
mov esi, action_header |
call print_text2 |
mov eax, servercommand+1 |
mov dl, '!' |
call print_text |
mov esi, has_quit_irc |
call print_text2 |
; TODO: check other channels on same server too! |
mov ebx, [window_print] |
mov esi, servercommand+1 |
call user_remove |
ret |
cmd_mode: |
add esi, 5 ; skip 'MODE ' |
push esi |
mov esi, action_header_short |
call print_text2 |
mov eax, servercommand+1 |
mov dl, ' ' |
call print_text |
mov esi, sets_mode |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
;;; TODO: change username if needed |
ret |
cmd_353: ; channel usernames reply |
add esi, 4 ; skip '353 ' |
call skip_nick |
inc esi ; channel type '*', '=' or '@' |
inc esi ; ' ' |
call find_window |
; now find window ptr and check if this is the first 353 message |
mov ebx, [window_print] |
test [ebx + window.flags], FLAG_RECEIVING_NAMES |
jnz .add |
or [ebx + window.flags], FLAG_RECEIVING_NAMES |
; mov [ebx + window.users], 0 |
; TODO: remove all users? |
.add: |
push esi |
call user_add |
pop esi |
.namesloop: |
lodsb |
test al, al |
jz .done |
cmp al, ' ' ; names list is separated with spaces |
jne .namesloop |
jmp .add |
.done: |
call redraw_channel_list |
ret |
cmd_366: ; channel usernames end |
add esi, 4 ; skip '366 ' |
call skip_nick |
call find_window |
mov ebx, [window_print] |
and [ebx + window.flags], not FLAG_RECEIVING_NAMES |
ret |
cmd_topic: |
add esi, 4 ; skip '332 ' |
call skip_nick |
call find_window |
push esi |
mov esi, action_header |
call print_text2 |
mov esi, str_topic |
call print_text2 |
pop esi |
call print_text2 |
mov esi, str_newline |
call print_text2 |
ret |
cmd_333: |
add esi, 4 ; skip '333 ' |
call skip_nick ;;;; |
call find_window |
; mov ecx, 2 ; number of spaces to find ;;; CHECKME |
; .loop: |
; lodsb |
; test al, al |
; je .fail |
; cmp al, ' ' |
; jne .loop |
; dec ecx |
; jnz .loop ; find some more spaces |
push esi |
mov esi, action_header |
call print_text2 |
mov esi, str_setby |
call print_text2 |
; pop esi |
; call print_text2 |
pop eax |
mov dl, '!' |
call print_text |
mov esi, str_newline |
call print_text2 |
.fail: |
ret |
cmd_322: |
add esi, 4 |
call skip_nick |
call print_text2 |
mov esi, str_newline |
call print_text2 |
ret |
cmd_323: |
ret |
/kernel/branches/net/applications/ircc/userparser.inc |
---|
0,0 → 1,318 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
user_parser: |
mov eax, [edit1.size] |
mov word [usercommand + eax], 0x0a0d ; terminate the line |
cmp byte[usercommand], '/' ; is it a server command ? |
je server_command |
; Ignore data commands when not connected. |
cmp [status], STATUS_CONNECTED |
jne sdts_ret |
; Ok, we said something, print it to our textbox |
; TODO: dont send if it's a server window? |
push [window_open] ; print to the current window |
pop [window_print] |
call window_refresh |
if TIMESTAMP |
call print_timestamp |
end if |
mov bl, '<' |
call print_character |
mov esi, user_nick |
call print_text2 |
mov bl,'>' |
call print_character |
mov bl,' ' |
call print_character |
mov eax, [edit1.size] |
mov byte[usercommand + eax],0 |
mov esi, usercommand |
call print_text2 |
mov bl, 10 |
call print_character |
; and now send it to the server |
mov dword[packetbuf], 'priv' |
mov dword[packetbuf+4], 'msg ' |
mov esi, [window_open] |
add esi, window.name |
mov edi, packetbuf+8 |
mov ecx, MAX_WINDOWNAME_LEN |
.loop: |
lodsb |
test al, al |
jz .done |
stosb |
dec ecx |
jnz .loop |
.done: |
mov ax, ' :' |
stosw |
mov esi, usercommand |
mov ecx, [edit1.size] |
inc ecx |
call recode |
mov al, 10 |
stosb |
lea esi, [edi - packetbuf] |
mcall send, [socketnum], packetbuf, , 0 |
sdts_ret: |
ret |
user_commands: |
dd 'nick', cmd_usr_nick |
dd 'real', cmd_usr_real |
dd 'serv', cmd_usr_server |
dd 'help', cmd_usr_help |
dd 'code', cmd_usr_code |
; TODO: All other commands require a connection to the server. |
dd 'quer', cmd_usr_quer |
dd 'quit', cmd_usr_quit |
.number = ($ - user_commands) / 8 |
server_command: |
mov eax, dword[usercommand+1] |
or eax, 0x20202020 |
mov edi, user_commands |
mov ecx, user_commands.number |
.loop: |
scasd |
je .got_cmd |
add edi, 4 |
dec ecx |
jnz .loop |
jmp cmd_usr_send ; If none of the previous commands, just send to server |
.got_cmd: |
jmp dword[edi] |
cmd_usr_quit: |
cmp [edit1.size], 5 |
je .ok |
jb cmd_usr_send |
cmp byte[usercommand+5], ' ' |
jne cmd_usr_send |
.ok: |
call cmd_usr_send |
mcall close, [socketnum] |
mov ecx, MAX_WINDOWS |
mov edi, windows |
.loop: |
mov [edi + window.flags], FLAG_CLOSE |
add edi, sizeof.window |
dec ecx |
jnz .loop |
ret |
cmd_usr_nick: |
cmp [edit1.size], 5 |
je .justprint |
cmp byte[usercommand+5], ' ' |
jne cmd_usr_send |
mov ecx, MAX_NICK_LEN |
mov esi, usercommand+6 |
mov edi, user_nick |
.loop: |
lodsb |
cmp al, 13 |
je .done |
stosb |
dec ecx |
jnz .loop |
.done: |
xor al, al |
stosb |
cmp [socketnum], 0 |
je .justprint |
lea esi, [edi - usercommand] |
mcall send, [socketnum], usercommand+1, , 0 |
.justprint: |
mov esi, str_nickchange |
call print_text2 |
mov esi, user_nick |
call print_text2 |
mov esi, str_dotnewline |
call print_text2 |
ret |
cmd_usr_real: |
cmp byte[usercommand+5], ' ' |
jne cmd_usr_send |
mov ecx, MAX_REAL_LEN |
mov esi, usercommand+6 |
mov edi, user_real_name |
.loop: |
lodsb |
cmp al, 13 |
je .done |
stosb |
dec ecx |
jnz .loop |
.done: |
xor al, al |
stosb |
mov esi, str_realchange |
call print_text2 |
mov esi, user_real_name |
call print_text2 |
mov esi, str_dotnewline |
call print_text2 |
ret |
cmd_usr_server: |
mov eax, dword[usercommand+5] ; check for 'er ', we only checked 'serv' |
or eax, 0x00002020 |
and eax, 0x00ffffff |
cmp eax, 'er ' |
jne cmd_usr_send |
mov ecx, [edit1.size] ; ok now set the address |
sub ecx, 8 |
mov esi, usercommand+8 |
push esi |
mov edi, irc_server_name |
rep movsb |
xor al, al |
stosb |
pop esi |
; set it also in window name |
mov ebx, [window_print] |
call window_set_name |
; now connect |
call socket_connect |
ret |
cmd_usr_quer: |
mov ecx, MAX_WINDOWS |
mov ebx, windows |
.loop: |
cmp [ebx + window.data_ptr], 0 |
je .found |
add ebx, sizeof.window |
dec ecx |
jnz .loop |
; error: no available channels ! FIXME |
ret |
.found: |
call window_create |
test eax, eax |
jz .error |
mov [ebx + window.data_ptr], eax |
mov esi, usercommand+7 |
call window_set_name |
mov [ebx + window.type], WINDOWTYPE_CHAT |
mov [ebx + window.flags], 0 |
.error: |
ret |
cmd_usr_help: |
mov esi, str_help |
call print_text2 |
ret |
cmd_usr_code: |
; TODO |
ret |
cmd_usr_send: |
mov esi, usercommand+1 |
mov ecx, [edit1.size] |
inc ecx |
mov edi, packetbuf |
call recode |
lea esi, [edi - packetbuf] |
mcall send, [socketnum], packetbuf, , 0 |
ret |
/kernel/branches/net/applications/ircc/users.inc |
---|
0,0 → 1,164 |
; esi is ptr to nick |
; ebx is ptr to window |
align 4 |
user_add: |
cmp [ebx + window.users], MAX_USERS |
jae fail |
mov edi, [ebx + window.data_ptr] |
add edi, window_data.names |
mov ebp, [ebx + window.users] |
inc ebp ; CHECKME |
push esi edi |
.restart: |
mov ecx, MAX_NICK_LEN |
.loop1: |
lodsb |
cmp al, '@' |
jne @f |
mov al, ' ' ; give @ highest priority |
@@: |
cmp al, 'A' |
jb @f |
cmp al, 'Z' |
ja @f |
add al, 'a' - 'A' ; convert to lowercase |
@@: |
dec ecx |
jz .got_it |
.loop2: |
mov dl, [edi] |
cmp dl, 0 |
je .got_it |
cmp dl, '@' |
jne @f |
mov dl, ' ' ; give @ highest priority |
@@: |
cmp dl, 'A' |
jb @f |
cmp dl, 'Z' |
ja @f |
add dl, 'a' - 'A' ; convert to lowercase |
@@: |
cmp al, dl |
jb .got_it |
je .check_next |
pop edi esi |
add edi, MAX_NICK_LEN |
push esi edi |
dec ebp |
jnz .restart |
.check_next: |
inc edi |
jmp .loop1 |
.got_it: |
pop edi esi |
; OK, insert it here.. |
; mov all trailing usernames by MAX_NICK_LEN bytes |
push esi edi |
mov esi, [ebx + window.data_ptr] |
add esi, window_data.names + MAX_NICK_LEN * (MAX_USERS - 1) |
mov ecx, esi |
sub ecx, edi |
add ecx, MAX_NICK_LEN |
shr ecx, 2 |
lea edi, [esi + MAX_NICK_LEN] |
std |
rep movsd |
cld |
pop edi esi |
; Now insert our new username |
mov ecx, MAX_NICK_LEN-1 |
.fill: |
lodsb |
cmp al, ' ' |
je .done |
cmp al, '!' |
je .done |
stosb |
loop .fill |
.done: |
xor al, al |
stosb |
inc [ebx + window.users] |
ret |
; esi is ptr to nick |
; ebx is ptr to window |
align 4 |
user_remove: |
call user_find |
jz fail |
lea esi, [edi + MAX_NICK_LEN] |
mov ecx, [ebx + window.data_ptr] |
add ecx, window_data.names + MAX_NICK_LEN * MAX_USERS |
sub ecx, esi |
shr ecx, 2 |
rep movsd |
dec [ebx + window.users] |
xor eax, eax |
ret |
; IN: |
; esi is ptr to nick |
; ebx is ptr to window |
; OUT: |
; edi is ptr to nick in userlist |
align 4 |
user_find: |
mov eax, [ebx + window.users] |
test eax, eax |
jz fail |
mov edi, [ebx + window.data_ptr] |
add edi, window_data.names |
.loop: |
push esi edi |
mov ecx, MAX_NICK_LEN |
repe cmpsb |
cmp byte[edi-1], 0 |
je .got_it |
; TODO: check byte[esi] too! |
pop edi esi |
add edi, MAX_NICK_LEN |
dec eax |
jnz .loop |
jmp fail |
.got_it: |
pop edi esi |
test edi, edi ; to clear zero flag |
ret |
fail: |
xor edi, edi |
ret |
/kernel/branches/net/applications/ircc/socket.inc |
---|
0,0 → 1,242 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
socket_connect: |
; cmp [status], STATUS_CONNECTED ; TODO |
; je disconnect |
; ignore if status is not "disconnected" |
cmp [status], STATUS_DISCONNECTED |
jne .nothing |
mov esi, str_connecting |
call print_text2 |
mov esi, irc_server_name |
call print_text2 |
mov esi, str_dotnewline |
call print_text2 |
; update status |
inc [status] ; was STATUS_DISCONNECTED, now STATUS_RESOLVING |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push irc_server_name |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz .fail_dns |
; fill in ip in sockstruct |
mov eax, [esi + addrinfo.ai_addr] |
mov eax, [eax + sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
; free allocated memory |
push esi |
call [freeaddrinfo] |
; update status |
inc [status] |
; connect |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
jz .fail |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
cmp eax, -1 |
jz .fail_refused |
.nothing: |
ret |
.fail: |
mov [status], STATUS_DISCONNECTED |
mov esi, str_sockerr |
call print_text2 |
ret |
.fail_dns: |
mov [status], STATUS_DISCONNECTED |
mov esi, str_dnserr |
call print_text2 |
ret |
.fail_refused: |
mov [status], STATUS_DISCONNECTED |
mov esi, str_refused |
call print_text2 |
ret |
socket_write_userinfo: |
; create packet in packetbuf |
mov edi, packetbuf |
mov eax, 'NICK' |
stosd |
mov al, ' ' |
stosb |
mov esi, user_nick |
mov ecx, MAX_NICK_LEN |
.loop: |
lodsb |
test al, al |
jz .done |
stosb |
dec ecx |
jnz .loop |
.done: |
mov ax, 0x0d0a |
stosw |
mov eax, 'USER' |
stosd |
mov al, ' ' |
stosb |
mov esi, user_nick |
mov ecx, MAX_NICK_LEN |
.loop2: |
lodsb |
test al, al |
jz .done2 |
stosb |
dec ecx |
jnz .loop2 |
.done2: |
mov eax, ' 8 *' |
stosd |
mov ax, ' :' |
stosw |
mov al, ' ' |
stosb |
mov esi, user_real_name |
mov ecx, MAX_REAL_LEN |
.loop3: |
lodsb |
test al, al |
jz .done3 |
stosb |
dec ecx |
jnz .loop3 |
.done3: |
mov ax, 0x0d0a |
stosw |
lea esi, [edi - packetbuf] |
mcall send, [socketnum], packetbuf, , 0 |
ret |
process_network_event: |
; values for status: 0, 1, 2, 3 |
mov eax, [status] |
dec eax |
; 0 = STATUS_DISCONNECTED - do nothing |
; (ignore network events if we are disconnected from network) |
js .nothing |
; 1 = STATUS_RESOLVING |
jz .nothing |
; 2 = STATUS_CONNECTING |
dec eax |
jz .connecting |
; 3 = STATUS_CONNECTED |
jmp .connected |
.nothing: |
ret |
.connecting: |
call socket_write_userinfo |
; The connection has been established, change status from "connecting" to "connected". |
inc [status] |
.connected: |
call read_incoming_data |
ret |
disconnect: |
cmp [status], STATUS_DISCONNECTED |
je .nothing |
mcall close, [socketnum] |
mov [status], STATUS_DISCONNECTED |
.nothing: |
ret |
read_incoming_data: |
pusha |
; TODO: read more data if we receive one full packet |
.nextpacket: |
mcall recv, [socketnum], packetbuf, 1024 ; read a packet |
inc eax ; check if we got one |
jz .done |
dec eax |
jz .done |
; ok we have data, now feed it to the recoder |
lea edx, [packetbuf + eax] ; edx = end pointer |
mov esi, packetbuf ; esi = start pointer |
.nextcommand: |
mov edi, servercommand |
.byteloop: |
call get_next_byte ; reads byte from [esi] to al |
jnc .nextpacket ; if CF is set, we need more data |
cmp al, 10 |
je .got_command |
cmp al, 13 |
je .got_command |
stosb |
jmp .byteloop |
; we have a command, call the serverparser |
.got_command: |
mov byte[edi], 0 ; mark the end of the command |
push esi edx |
call server_parser |
pop edx esi |
jmp .nextcommand |
.done: |
popa |
ret |
/kernel/branches/net/applications/ircc/encodings.inc |
---|
0,0 → 1,317 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
get_next_byte: |
; Load next byte from the packet, translating to cp866 if necessary |
; At input esi = pointer to data, edx = limit of data |
; Output is either (translated) byte in al with CF set or CF cleared. |
mov eax, [encoding] |
jmp [get_byte_table+eax*4] |
get_byte_cp866: |
cmp esi, edx |
jae .nothing |
lodsb |
.nothing: |
ret |
get_byte_cp1251: |
cmp esi, edx |
jae .nothing |
lodsb |
cmp al, 0x80 |
jb @f |
and eax, 0x7F |
mov al, [cp1251_table+eax] |
@@: |
stc |
.nothing: |
ret |
get_byte_utf8: |
; UTF8 decoding is slightly complicated. |
; One character can occupy one or more bytes. |
; The boundary in packets theoretically can be anywhere in data, |
; so this procedure keeps internal state between calls and handles |
; one byte at a time, looping until character is read or packet is over. |
; Globally, there are two distinct tasks: decode byte sequence to unicode char |
; and convert this unicode char to our base encoding (that is cp866). |
; 1. Check that there are data. |
cmp esi, edx |
jae .nothing |
; 2. Load byte. |
lodsb |
movzx ecx, al |
; 3. Bytes in an UTF8 sequence can be of any of three types. |
; If most significant bit is cleared, sequence is one byte and usual ASCII char. |
; First byte of a sequence must be 11xxxxxx, other bytes are 10yyyyyy. |
and al, 0xC0 |
jns .single_byte |
jp .first_byte |
; 4. This byte is not first in UTF8 sequence. |
; 4a. Check that the sequence was started. If no, it is invalid byte |
; and we simply ignore it. |
cmp [utf8_bytes_rest], 0 |
jz get_byte_utf8 |
; 4b. Otherwise, it is really next byte and it gives some more bits of char. |
mov eax, [utf8_char] |
shl eax, 6 |
lea eax, [eax+ecx-0x80] |
; 4c. Decrement number of bytes rest in the sequence. |
; If it goes to zero, character is read, so return it. |
dec [utf8_bytes_rest] |
jz .got_char |
mov [utf8_char], eax |
jmp get_byte_utf8 |
; 5. If the byte is first in UTF8 sequence, calculate the number of leading 1s |
; - it equals total number of bytes in the sequence; some other bits rest for |
; leading bits in the character. |
.first_byte: |
mov eax, -1 |
@@: |
inc eax |
add cl, cl |
js @b |
mov [utf8_bytes_rest], eax |
xchg eax, ecx |
inc ecx |
shr al, cl |
mov [utf8_char], eax |
jmp get_byte_utf8 |
; 6. If the byte is ASCII char, it is the character. |
.single_byte: |
xchg eax, ecx |
.got_char: |
; We got the character, now abandon a possible sequence in progress. |
and [utf8_bytes_rest], 0 |
; Now second task. The unicode character is in eax, and now we shall convert it |
; to cp866. |
cmp eax, 0x80 |
jb .done |
; 0x410-0x43F -> 0x80-0xAF, 0x440-0x44F -> 0xE0-0xEF, 0x401 -> 0xF0, 0x451 -> 0xF1 |
cmp eax, 0x401 |
jz .YO |
cmp eax, 0x451 |
jz .yo |
cmp eax, 0x410 |
jb .unrecognized |
cmp eax, 0x440 |
jb .part1 |
cmp eax, 0x450 |
jae .unrecognized |
sub al, (0x40-0xE0) and 0xFF |
ret |
.part1: |
sub al, 0x10-0x80 |
.nothing: |
.done: |
ret |
.unrecognized: |
mov al, '?' |
stc |
ret |
.YO: |
mov al, 0xF0 |
stc |
ret |
.yo: |
mov al, 0xF1 |
stc |
ret |
print_character: |
pusha |
cmp bl, 13 ; line beginning |
jne nobol |
mov ecx, [pos] |
inc ecx |
boll1: |
dec ecx |
mov eax, ecx |
xor edx, edx |
mov ebx, [textbox_width] |
div ebx |
test edx, edx |
jnz boll1 |
mov [pos], ecx |
jmp newdata |
nobol: |
cmp bl, 10 ; line down |
jne nolf |
addx1: |
inc [pos] |
mov eax, [pos] |
xor edx, edx |
mov ecx, [textbox_width] |
div ecx |
test edx, edx |
jnz addx1 |
mov eax, [pos] |
jmp cm1 |
nolf: |
no_lf_ret: |
cmp bl, 15 ; character |
jbe newdata |
mov eax, [irc_data] |
shl eax, 8 |
mov al, bl |
mov [irc_data], eax |
mov eax, [pos] |
;---- draw data |
pusha |
and ebx, 0xff |
add eax, [text_start] |
mov [eax], bl |
popa |
;---- draw data |
mov eax, [pos] |
inc eax |
cm1: |
mov ebx, [scroll+4] |
imul ebx, [textbox_width] |
cmp eax, ebx |
jb noeaxz |
mov esi, [text_start] |
add esi, [textbox_width] |
mov edi, [text_start] |
mov ecx, ebx |
rep movsb |
mov esi, [text_start] |
mov ecx, [textbox_width] |
imul ecx, 61 |
add esi, ecx |
mov edi, [text_start] |
mov ecx, [textbox_width] |
imul ecx, 60 |
add edi, ecx |
mov ecx, ebx |
rep movsb |
mov eax, ebx |
sub eax, [textbox_width] |
noeaxz: |
mov [pos], eax |
newdata: |
mov eax, [window_print] |
or [eax + window.flags], FLAG_UPDATED |
popa |
ret |
recode_to_cp866: |
rep movsb |
ret |
recode_to_cp1251: |
xor eax, eax |
jecxz .nothing |
.loop: |
lodsb |
cmp al,0x80 |
jb @f |
mov al, [cp866_table-0x80+eax] |
@@: stosb |
loop .loop |
.nothing: |
ret |
recode_to_utf8: |
jecxz .nothing |
.loop: |
lodsb |
cmp al, 0x80 |
jb .single_byte |
and eax, 0x7F |
mov ax, [utf8_table+eax*2] |
stosw |
loop .loop |
ret |
.single_byte: |
stosb |
loop .loop |
.nothing: |
ret |
recode: |
mov eax, [encoding] |
jmp [recode_proc+eax*4] |
encoding dd UTF8 |
recode_proc dd recode_to_cp866, recode_to_cp1251, recode_to_utf8 |
get_byte_table dd get_byte_cp866, get_byte_cp1251, get_byte_utf8 |
cp1251_table: |
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; 8 |
db '?','?','?','?','?',$F9,'?','?' , '?','?','?','?','?','?','?','?' ; 9 |
db '?',$F6,$F7,'?',$FD,'?','?','?' , $F0,'?',$F2,'?','?','?','?',$F4 ; A |
db $F8,'?','?','?','?','?','?',$FA , $F1,$FC,$F3,'?','?','?','?',$F5 ; B |
db $80,$81,$82,$83,$84,$85,$86,$87 , $88,$89,$8A,$8B,$8C,$8D,$8E,$8F ; C |
db $90,$91,$92,$93,$94,$95,$96,$97 , $98,$99,$9A,$9B,$9C,$9D,$9E,$9F ; D |
db $A0,$A1,$A2,$A3,$A4,$A5,$A6,$A7 , $A8,$A9,$AA,$AB,$AC,$AD,$AE,$AF ; E |
db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; F |
; 0 1 2 3 4 5 6 7 8 9 A B C D E F |
utf8_table: |
times 80h dw 0x98C3 ; default placeholder |
; 0x80-0xAF -> 0x90D0-0xBFD0 |
repeat 0x30 |
store byte 0xD0 at utf8_table+2*(%-1) |
store byte 0x90+%-1 at utf8_table+2*%-1 |
end repeat |
; 0xE0-0xEF -> 0x80D1-0x8FD1 |
repeat 0x10 |
store byte 0xD1 at utf8_table+2*(0xE0-0x80+%-1) |
store byte 0x80+%-1 at utf8_table+2*(0xE0-0x80+%)-1 |
end repeat |
; 0xF0 -> 0x81D0, 0xF1 -> 0x91D1 |
store dword 0x91D181D0 at utf8_table+2*(0xF0-0x80) |
cp866_table: |
db $C0,$C1,$C2,$C3,$C4,$C5,$C6,$C7 , $C8,$C9,$CA,$CB,$CC,$CD,$CE,$CF ; 8 |
db $D0,$D1,$D2,$D3,$D4,$D5,$D6,$D7 , $D8,$D9,$DA,$DB,$DC,$DD,$DE,$DF ; 9 |
db $E0,$E1,$E2,$E3,$E4,$E5,$E6,$E7 , $E8,$E9,$EA,$EB,$EC,$ED,$EE,$EF ; A |
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; B |
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; C |
db '?','?','?','?','?','?','?','?' , '?','?','?','?','?','?','?','?' ; D |
db $F0,$F1,$F2,$F3,$F4,$F5,$F6,$F7 , $F8,$F9,$FA,$FB,$FC,$FD,$FE,$FF ; E |
db $A8,$B8,$AA,$BA,$AF,$BF,$A1,$A2 , $B0,$95,$B7,'?',$B9,$A4,'?','?' ; F |
; 0 1 2 3 4 5 6 7 8 9 A B C D E F |
/kernel/branches/net/applications/ircc/ircc.ini |
---|
0,0 → 1,8 |
[user] |
nick = kolibri_user |
realname = tetten |
[colors] |
action1 = 0x000000aa |
action2 = 0x0000aa00 |
action3 = 0x00aa0000 |
/kernel/branches/net/applications/libio.inc |
---|
0,0 → 1,113 |
;;================================================================================================;; |
;;//// libio.inc //// (c) mike.dld, 2007-2008 ////////////////////////////////////////////////////;; |
;;================================================================================================;; |
;; ;; |
;; This file is part of Common development libraries (Libs-Dev). ;; |
;; ;; |
;; Libs-Dev is free software: you can redistribute it and/or modify it under the terms of the GNU ;; |
;; Lesser General Public License as published by the Free Software Foundation, either version 2.1 ;; |
;; of the License, or (at your option) any later version. ;; |
;; ;; |
;; Libs-Dev 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 ;; |
;; Lesser General Public License for more details. ;; |
;; ;; |
;; You should have received a copy of the GNU Lesser General Public License along with Libs-Dev. ;; |
;; If not, see <http://www.gnu.org/licenses/>. ;; |
;; ;; |
;;================================================================================================;; |
O_BINARY = 00000000b |
O_READ = 00000001b |
O_WRITE = 00000010b |
O_CREATE = 00000100b |
O_SHARE = 00001000b |
O_TEXT = 00010000b |
SEEK_SET = 0 |
SEEK_CUR = 1 |
SEEK_END = 2 |
struct FileDateTime |
union |
time dd ? |
struct |
sec db ? |
min db ? |
hour db ? |
ends |
ends |
union |
date dd ? |
struct |
day db ? |
month db ? |
year dw ? |
ends |
ends |
ends |
struct FileInfoBlock |
Function dd ? |
Position dd ? |
Flags dd ? |
Count dd ? |
Buffer dd ? |
db ? |
FileName dd ? |
ends |
struct FileInfoHeader |
Version dd ? |
FilesRead dd ? |
FilesCount dd ? |
rd 5 |
ends |
struct FileInfoA |
Attributes dd ? |
Flags dd ? |
DateCreate FileDateTime |
DateAccess FileDateTime |
DateModify FileDateTime |
union |
FileSize dq ? |
struct |
FileSizeLow dd ? |
FileSizeHigh dd ? |
ends |
ends |
FileName rb 264 |
ends |
struct FileInfoW |
Attributes dd ? |
Flags dd ? |
DateCreate FileDateTime |
DateAccess FileDateTime |
DateModify FileDateTime |
union |
FileSize dq ? |
struct |
FileSizeLow dd ? |
FileSizeHigh dd ? |
ends |
ends |
FileName rw 264 |
ends |
virtual at 0 |
FileInfo FileInfoA |
FileInfo fix FileInfoA |
sizeof.FileInfo fix sizeof.FileInfoA |
end virtual |
FA_READONLY = 00000001b |
FA_HIDDEN = 00000010b |
FA_SYSTEM = 00000100b |
FA_LABEL = 00001000b |
FA_FOLDER = 00010000b |
FA_ARCHIVED = 00100000b |
FA_NORMAL = 01000000b |
FA_ANY = 01111111b |
/kernel/branches/net/applications/macros.inc |
---|
0,0 → 1,588 |
@^ fix macro comment { |
^@ fix } |
; ------------------------- |
macro library [lname,fname] |
{ |
forward |
dd __#lname#_library_table__,__#lname#_library_name__ |
common |
dd 0 |
forward |
align 4 |
__#lname#_library_name__ db fname,0 |
} |
macro import lname,[name,sname] |
{ |
common |
align 4 |
__#lname#_library_table__: |
forward |
if used name |
name dd __#name#_import_name__ |
end if |
common |
dd 0 |
forward |
if used name |
align 4 |
__#name#_import_name__ db sname,0 |
end if |
} |
macro export [name,sname] |
{ |
forward |
dd __#name#_export_name__,name |
common |
dd 0 |
forward |
align 4 |
__#name#_export_name__ db sname,0 |
} |
; ------------------------- |
macro m2m dest,src { |
push src |
pop dest |
} |
macro iglobal { |
IGlobals equ IGlobals, |
macro __IGlobalBlock { } |
macro uglobal { |
UGlobals equ UGlobals, |
macro __UGlobalBlock { } |
endg fix } ; Use endg for ending iglobal and uglobal blocks. |
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 \} } |
uglobal |
endg |
iglobal |
endg |
; new application structure |
macro meos_app_start |
{ |
use32 |
org 0x0 |
db 'MENUET01' |
dd 0x01 |
dd __start |
dd __end |
dd __memory |
dd __stack |
if used __params & ~defined __params |
dd __params |
else |
dd 0x0 |
end if |
dd 0x0 |
} |
MEOS_APP_START fix meos_app_start |
macro code |
{ |
__start: |
} |
CODE fix code |
macro data |
{ |
__data: |
IncludeIGlobals |
} |
DATA fix data |
macro udata |
{ |
if used __params & ~defined __params |
__params: |
db 0 |
__end: |
rb 255 |
else |
__end: |
end if |
__udata: |
IncludeUGlobals |
} |
UDATA fix udata |
macro meos_app_end |
{ |
align 32 |
rb 2048 |
__stack: |
__memory: |
} |
MEOS_APP_END fix meos_app_end |
; macro for defining multiline text data |
struc mstr [sstring] |
{ |
forward |
local ssize |
virtual at 0 |
db sstring |
ssize = $ |
end virtual |
dd ssize |
db sstring |
common |
dd -1 |
} |
; macro for defining multiline text data |
struc mls [sstring] |
{ |
forward |
local ssize |
virtual at 0 |
db sstring ; mod |
ssize = $ |
end virtual |
db ssize |
db sstring |
common |
db -1 ; mod |
} |
; strings |
macro sz name,[data] { ; from MFAR [mike.dld] |
common |
if used name |
name db data |
.size = $-name |
end if |
} |
macro lsz name,[lng,data] { ; from MFAR [mike.dld] |
common |
if used name |
label name |
forward |
if lang eq lng |
db data |
end if |
common |
.size = $-name |
end if |
} |
macro szc name,elsz,[data] { ; from MFAR [mike.dld] |
common |
local s,m |
m = 0 |
if used name |
label name |
forward |
virtual at 0 |
db data |
s = $ |
end virtual |
d#elsz s |
if m < s |
m = s |
end if |
db data |
common |
.size = $-name |
.maxl = m |
end if |
} |
macro lszc name,elsz,[lng,data] { ; from MFAR [mike.dld] |
common |
local s,m,c |
m = 0 |
c = 0 |
if used name |
label name |
forward |
if lang eq lng |
virtual at 0 |
db data |
s = $ |
end virtual |
d#elsz s |
if m < s |
m = s |
end if |
db data |
c = c+1 |
end if |
common |
.size = $-name |
.maxl = m |
.count = c |
end if |
} |
; easy system call macro |
macro mpack dest, hsrc, lsrc |
{ |
if (hsrc eqtype 0) & (lsrc eqtype 0) |
mov dest, (hsrc) shl 16 + lsrc |
else |
if (hsrc eqtype 0) & (~lsrc eqtype 0) |
mov dest, (hsrc) shl 16 |
add dest, lsrc |
else |
mov dest, hsrc |
shl dest, 16 |
add dest, lsrc |
end if |
end if |
} |
macro __mov reg,a,b { ; mike.dld |
if (~a eq)&(~b eq) |
mpack reg,a,b |
else if (~a eq)&(b eq) |
mov reg,a |
end if |
} |
include 'config.inc' |
;__CPU_type equ p5 |
SYSENTER_VAR equ 0 |
macro mcall a,b,c,d,e,f { ; mike.dld, updated by Ghost for Fast System Calls |
local ..ret_point |
__mov eax,a |
__mov ebx,b |
__mov ecx,c |
__mov edx,d |
__mov esi,e |
__mov edi,f |
if __CPU_type eq p5 |
int 0x40 |
else |
if __CPU_type eq p6 |
push ebp |
mov ebp, esp |
push ..ret_point ; it may be 2 or 5 byte |
sysenter |
..ret_point: |
pop edx |
pop ecx |
else |
if __CPU_type eq k6 |
push ecx |
syscall |
pop ecx |
else |
display 'ERROR : unknown CPU type (set to p5)', 10, 13 |
__CPU_type equ p5 |
int 0x40 |
end if |
end if |
end if |
} |
; ------------------------- |
macro header a,[b] { |
common |
use32 |
org 0 |
db 'MENUET',a |
forward |
if b eq |
dd 0 |
else |
dd b |
end if } |
macro section name { align 16 |
label name } |
macro func name { |
if ~used name |
display 'FUNC NOT USED: ',`name,13,10 |
else |
align 4 |
name: |
;diff16 `name,0,name |
;pushad |
;pushfd |
;dps `name |
;newline |
;mcall 5,1 |
;popfd |
;popad |
} |
macro endf { end if } |
macro diff16 title,l1,l2 |
{ |
local s,d |
s = l2-l1 |
display title,': 0x' |
repeat 8 |
d = '0' + s shr ((8-%) shl 2) and $0F |
if d > '9' |
d = d + 'A'-'9'-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 |
} |
; optimize the code for size |
__regs fix <eax,ebx,ecx,edx,esi,edi,ebp,esp> |
macro add arg1,arg2 |
{ |
if (arg2 eqtype 0) |
if (arg2) = 1 |
inc arg1 |
else |
add arg1,arg2 |
end if |
else |
add arg1,arg2 |
end if |
} |
macro sub arg1,arg2 |
{ |
if (arg2 eqtype 0) |
if (arg2) = 1 |
dec arg1 |
else |
sub arg1,arg2 |
end if |
else |
sub arg1,arg2 |
end if |
} |
macro mov arg1,arg2 |
{ |
if (arg1 in __regs) & ((arg2 eqtype 0) | (arg2 eqtype '0')) |
if (arg2) = 0 |
xor arg1,arg1 |
else if (arg2) = 1 |
xor arg1,arg1 |
inc arg1 |
else if (arg2) = -1 |
or arg1,-1 |
else if (arg2) > -128 & (arg2) < 128 |
push arg2 |
pop arg1 |
else |
mov arg1,arg2 |
end if |
else |
mov arg1,arg2 |
end if |
} |
macro RGB [a] { |
common |
match (r=,g=,b),a \{ |
\dd ((r) shl 16) or ((g) shl 8) or (b) |
\} |
} |
struc POINT _t,_dx,_dy { |
.x _t _dx |
.y _t _dy |
} |
; structure definition helper |
include 'struct.inc' |
struct RECT |
left dd ? |
top dd ? |
right dd ? |
bottom dd ? |
ends |
struct BOX |
left dd ? |
top dd ? |
width dd ? |
height dd ? |
ends |
; structures used in MeOS |
struct process_information |
cpu_usage dd ? ; +0 |
window_stack_position dw ? ; +4 |
window_stack_value dw ? ; +6 |
dw ? ; +8 |
process_name rb 12 ; +10 |
memory_start dd ? ; +22 |
used_memory dd ? ; +26 |
PID dd ? ; +30 |
box BOX ; +34 |
slot_state dw ? ; +50 |
dw ? ; +52 |
client_box BOX ; +54 |
wnd_state db ? ; +70 |
rb (1024-71) |
ends |
struct system_colors |
frame dd ? |
grab dd ? |
grab_button dd ? |
grab_button_text dd ? |
grab_text dd ? |
work dd ? |
work_button dd ? |
work_button_text dd ? |
work_text dd ? |
work_graph dd ? |
ends |
struct FILEDATE |
Second db ? |
Minute db ? |
Hour db ? |
db ? |
Day db ? |
Month db ? |
Year dw ? |
ends |
struct FILEINFO |
Attributes dd ? |
IsUnicode db ? |
db 3 dup(?) |
DateCreate FILEDATE |
DateAccess FILEDATE |
DateModify FILEDATE |
Size dq ? |
ends |
if __CPU_type eq p5 ; CMOVcc isnt supported on the P5 |
cmove fix cmovz |
macro cmovz reg1, reg2 { |
local .jumpaddr |
jnz .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
cmovne fix cmovnz |
macro cmovnz reg1, reg2 { |
local .jumpaddr |
jz .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovg reg1, reg2 { |
local .jumpaddr |
jle .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovl reg1, reg2 { |
local .jumpaddr |
jge .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
end if |
; constants |
; events |
EV_IDLE = 0 |
EV_TIMER = 0 |
EV_REDRAW = 1 |
EV_KEY = 2 |
EV_BUTTON = 3 |
EV_EXIT = 4 |
EV_BACKGROUND = 5 |
EV_MOUSE = 6 |
EV_IPC = 7 |
EV_STACK = 8 |
; event mask bits for function 40 |
EVM_REDRAW = 1b |
EVM_KEY = 10b |
EVM_BUTTON = 100b |
EVM_EXIT = 1000b |
EVM_BACKGROUND = 10000b |
EVM_MOUSE = 100000b |
EVM_IPC = 1000000b |
EVM_STACK = 10000000b |
EVM_DEBUG = 100000000b |
EVM_STACK2 = 1000000000b |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/zeroconf/network.ini |
---|
0,0 → 1,9 |
[ipconfig] |
; type should be static or zeroconf |
; zeroconf means the service first tries to contact a DHCP server |
; If dhcp is not available, it switches to link-local |
type = zeroconf |
ip = 192.168.1.150 |
gateway = 192.168.1.1 |
dns = 192.168.1.1 |
subnet = 255.255.255.0 |
/kernel/branches/net/applications/zeroconf/zeroconf.asm |
---|
0,0 → 1,620 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; zeroconfig.asm - Zeroconfig service for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; Some code contributed by Derpenguin ;; |
;; ;; |
;; DHCP code is based on that by Mike Hibbet ;; |
; (DHCP client for menuetos) ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 0x01 ; header version |
dd START ; start of code |
dd IM_END ; size of image |
dd (I_END+0x100) ; memory for app |
dd (I_END+0x100) ; esp |
dd 0, 0 ; I_Param, I_Path |
; CONFIGURATION |
TIMEOUT = 60 ; in seconds |
BUFFER = 1024 ; in bytes |
__DEBUG__ = 1 ; enable/disable |
__DEBUG_LEVEL__ = 1 ; 1 = all, 2 = errors |
; CONFIGURATION FOR LINK-LOCAL |
PROBE_WAIT = 1 ; second (initial random delay) |
PROBE_MIN = 1 ; second (minimum delay till repeated probe) |
PROBE_MAX = 2 ; seconds (maximum delay till repeated probe) |
PROBE_NUM = 3 ; (number of probe packets) |
ANNOUNCE_NUM = 2 ; (number of announcement packets) |
ANNOUNCE_INTERVAL = 2 ; seconds (time between announcement packets) |
ANNOUNCE_WAIT = 2 ; seconds (delay before announcing) |
MAX_CONFLICTS = 10 ; (max conflicts before rate limiting) |
RATE_LIMIT_INTERVAL = 60 ; seconds (delay between successive attempts) |
DEFEND_INTERVAL = 10 ; seconds (min. wait between defensive ARPs) |
include '../proc32.inc' |
include '../macros.inc' |
include '../debug-fdo.inc' |
include '../network.inc' |
include 'dhcp.inc' |
include '../dll.inc' |
Ip2dword: |
push edx |
; This code validates if the query is an IP containing 4 numbers and 3 dots |
xor al, al ; make al (dot count) zero |
@@: |
cmp byte[edx],'0' ; check if this byte is a number, if not jump to no_IP |
jl no_IP ; |
cmp byte[edx],'9' ; |
jg no_IP ; |
inc edx ; the byte was a number, so lets check the next byte |
cmp byte[edx],0 ; is this byte zero? (have we reached end of query?) |
jz @f ; jump to next @@ then |
cmp byte[edx],':' |
jz @f |
cmp byte[edx],'.' ; is this byte a dot? |
jne @r ; if not, jump to previous @@ |
inc al ; the byte was a dot so increment al(dot count) |
inc edx ; next byte |
jmp @r ; lets check for numbers again (jump to previous @@) |
@@: ; we reach this when end of query reached |
cmp al,3 ; check if there where 3 dots |
jnz no_IP ; if not, jump to no_IP |
; The following code will convert this IP into a dword and output it in eax |
; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1 |
pop esi ; edx (query address) was pushed onto stack and is now popped in esi |
xor edx, edx ; result |
xor eax, eax ; current character |
xor ebx, ebx ; current byte |
.outer_loop: |
shl edx, 8 |
add edx, ebx |
xor ebx, ebx |
.inner_loop: |
lodsb |
test eax, eax |
jz .finish |
cmp al, '.' |
jz .outer_loop |
sub eax, '0' |
imul ebx, 10 |
add ebx, eax |
jmp .inner_loop |
.finish: |
shl edx, 8 |
add edx, ebx |
bswap edx ; we want little endian order |
ret |
no_IP: |
pop edx |
xor edx, edx |
ret |
START: |
mcall 40, EVM_STACK2 |
DEBUGF 1,">Zero-config service loaded\n" |
.wait: |
mcall 76, API_ETH + 4 ; get MAC of ethernet interface 0 |
cmp eax, -1 |
jne .start |
mcall 10 |
jmp .wait |
.start: |
mov word[MAC], bx |
mov dword[MAC+2], eax |
DEBUGF 1,"->MAC: %x-%x-%x-%x-%x-%x\n", [MAC+0]:2, [MAC+1]:2, [MAC+2]:2, [MAC+3]:2, [MAC+4]:2, [MAC+5]:2 |
mcall 40, EVM_STACK |
mcall 68, 11 |
stdcall dll.Load,@IMPORT |
or eax, eax |
jnz try_dhcp |
invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0 |
cmp dword[inibuf], 'stat' |
jne try_dhcp |
invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0 |
mov edx, inibuf |
call Ip2dword |
mcall 76, API_IPv4 + 3, edx |
invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0 |
mov edx, inibuf |
call Ip2dword |
mcall 76, API_IPv4 + 9, edx |
invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0 |
mov edx, inibuf |
call Ip2dword |
mcall 76, API_IPv4 + 5, edx |
invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0 |
mov edx, inibuf |
call Ip2dword |
mcall 76, API_IPv4 + 7, edx |
mcall -1 |
try_dhcp: |
DEBUGF 1,"->Trying DHCP\n" |
mcall 75, 0, AF_INET4, SOCK_DGRAM, 0 ; open socket (parameters: domain, type, reserved) |
cmp eax, -1 |
je error |
mov [socketNum], eax |
DEBUGF 1,"->Socket %x opened\n", eax |
mcall 75, 2, [socketNum], sockaddr1, 18 ; bind socket to local port 68 |
cmp eax, -1 |
je error |
DEBUGF 1,"->Socket Bound to local port 68\n" |
mcall 75, 4, [socketNum], sockaddr2, 18 ; connect to 255.255.255.255 on port 67 |
cmp eax, -1 |
je error |
DEBUGF 1,"->Connected to 255.255.255.255 on port 67\n" |
mov [dhcpMsgType], 0x01 ; DHCP discover |
mov [dhcpLease], esi ; esi is still -1 (-1 = forever) |
mcall 26, 9 ; Get system time |
imul eax, 100 |
mov [currTime], eax |
build_request: ; Creates a DHCP request packet. |
DEBUGF 1,"->Building request\n" |
stdcall mem.Alloc, BUFFER |
mov [dhcpMsg], eax |
test eax, eax |
jz dhcp_error |
;;; todo: skip this bullcrap |
mov edi, eax |
mov ecx, BUFFER |
xor eax, eax |
rep stosb |
;; todo: put this in a buffer instead of writing bytes and words! |
mov edx, [dhcpMsg] |
; Boot protocol legacy |
mov [edx], byte 0x01 ; Boot request |
mov [edx+1], byte 0x01 ; Ethernet |
mov [edx+2], byte 0x06 ; Ethernet h/w len |
mov [edx+4], dword 0x11223344 ; xid ;;;;;;; |
mov eax, [currTime] |
mov [edx+8], eax ; secs, our uptime |
mov [edx+10], byte 0x80 ; broadcast flag set |
mov eax, dword [MAC] ; first 4 bytes of MAC |
mov [edx+28],dword eax |
mov ax, word [MAC+4] ; last 2 bytes of MAC |
mov [edx+32],word ax |
; DHCP extension |
mov [edx+236], dword 0x63538263 ; magic cookie |
mov [edx+240], word 0x0135 ; option DHCP msg type |
mov al, [dhcpMsgType] |
mov [edx+240+2], al |
mov [edx+240+3], word 0x0433 ; option Lease time = infinity |
mov eax, [dhcpLease] |
mov [edx+240+5], eax |
mov [edx+240+9], word 0x0432 ; option requested IP address |
mov eax, [dhcp.ip] |
mov [edx+240+11], eax |
mov [edx+240+15], word 0x0437 ; option request list |
mov [edx+240+17], dword 0x0f060301 |
cmp [dhcpMsgType], byte 0x01 ; Check which msg we are sending |
jne request_options |
mov [edx+240+21], byte 0xff ; "Discover" options |
mov [dhcpMsgLen], dword 262 ; end of options marker |
jmp send_dhcpmsg |
request_options: |
mov [edx+240+21], word 0x0436 ; server IP |
mov eax, [dhcpServerIP] |
mov [edx+240+23], eax |
mov [edx+240+27], byte 0xff ; end of options marker |
mov [dhcpMsgLen], dword 268 |
send_dhcpmsg: |
mcall 75, 6, [socketNum], [dhcpMsg], [dhcpMsgLen] ; write to socket ( send broadcast request ) |
mov eax, [dhcpMsg] ; Setup the DHCP buffer to receive response |
mov [dhcpMsgLen], eax ; Used as a pointer to the data |
mcall 23, TIMEOUT*10 ; wait for data |
read_data: ; we have data - this will be the response |
mcall 75, 7, [socketNum], [dhcpMsg], BUFFER ; read data from socket |
DEBUGF 1,"->%d bytes received\n", eax |
cmp eax, -1 |
je dhcp_error |
mov [dhcpMsgLen], eax |
; depending on which msg we sent, handle the response |
; accordingly. |
; If the response is to a dhcp discover, then: |
; 1) If response is DHCP OFFER then |
; 1.1) record server IP, lease time & IP address. |
; 1.2) send a request packet |
; If the response is to a dhcp request, then: |
; 1) If the response is DHCP ACK then |
; 1.1) extract the DNS & subnet fields. Set them in the stack |
cmp [dhcpMsgType], 0x01 ; did we send a discover? |
je discover |
cmp [dhcpMsgType], 0x03 ; did we send a request? |
je request |
call dhcp_end ; we should never reach here ;) |
jmp exit |
discover: |
call parse_response |
cmp [dhcpMsgType], 0x02 ; Was the response an offer? |
je send_request |
call dhcp_end |
jmp link_local |
send_request: |
mov [dhcpMsgType], 0x03 ; make it a request |
jmp build_request |
request: |
call parse_response |
cmp [dhcpMsgType], 0x05 ; Was the response an ACK? It should be |
jne read_data ; NO - read next packets |
call dhcp_end |
mcall 76, API_IPv4 + 3, [dhcp.ip] ; ip |
mcall 76, API_IPv4 + 5, [dhcp.dns] ; dns |
mcall 76, API_IPv4 + 7, [dhcp.subnet] ; subnet |
mcall 76, API_IPv4 + 9, [dhcp.gateway] ; gateway |
jmp exit |
dhcp_end: |
mcall close, [socketNum] |
stdcall mem.Free, [dhcpMsg] |
ret |
;*************************************************************************** |
; Function |
; parseResponse |
; |
; Description |
; extracts the fields ( client IP address and options ) from |
; a DHCP response |
; The values go into |
; dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP, |
; dhcpDNSIP, dhcpSubnet |
; The message is stored in dhcpMsg |
; |
;*************************************************************************** |
parse_response: |
DEBUGF 1,"Data received, parsing response\n" |
mov edx, [dhcpMsg] |
push dword [edx+16] |
pop [dhcp.ip] |
DEBUGF 1,"Client: %u.%u.%u.%u\n", [edx+16]:1, [edx+17]:1, [edx+18]:1, [edx+19]:1 |
; TODO: check if there really are options |
mov al, 240 ; Point to first option |
movzx ecx, al |
.next_option: |
add edx, ecx |
mov al, [edx] ; get message identifier |
cmp al, 0xff ; End of options? |
je .done |
cmp al, 0 |
je .pad |
; TODO: check if we still are inside the buffer |
inc edx |
movzx ecx, byte [edx] ; get data length |
inc edx ; point to data |
cmp al, dhcp_msg_type ; Msg type is a single byte option |
je .msgtype |
cmp al, dhcp_dhcp_server_id |
je .server |
cmp al, dhcp_address_time |
je .lease |
cmp al, dhcp_subnet_mask |
je .subnet |
cmp al, dhcp_router |
je .router |
cmp al, dhcp_domain_server |
je .dns |
DEBUGF 1,"Unsupported DHCP option: %u\n", al |
jmp .next_option |
.pad: |
xor ecx, ecx |
inc ecx |
jmp .next_option |
.msgtype: |
mov al, [edx] |
mov [dhcpMsgType], al |
DEBUGF 1,"DHCP Msg type: %u\n", al |
jmp .next_option ; Get next option |
.server: |
mov eax, [edx] |
mov [dhcpServerIP], eax |
DEBUGF 1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
jmp .next_option |
.lease: |
pusha |
mov eax,[edx] |
bswap eax |
mov [dhcpLease],eax |
DEBUGF 1,"lease: %d\n",eax |
popa |
jmp .next_option |
.subnet: |
push dword [edx] |
pop [dhcp.subnet] |
DEBUGF 1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
jmp .next_option |
.router: |
push dword [edx] |
pop [dhcp.gateway] |
DEBUGF 1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
jmp .next_option |
.dns: |
push dword [edx] |
pop [dhcp.dns] |
DEBUGF 1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
jmp .next_option |
.done: |
ret |
dhcp_error: |
call dhcp_end |
link_local: |
call random |
mov cx, ax |
shl ecx, 16 |
mov cx, 0xfea9 ; IP 169.254.0.0 link local net, see RFC3927 |
mcall 76, API_IPv4 + 3, ecx ; mask is 255.255.0.0 |
DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n", [generator+0]:1, [generator+1]:1 |
mcall 76, API_IPv4 + 7, 0xffff |
mcall 76, API_IPv4 + 9, 0x0 |
mcall 76, API_IPv4 + 5, 0x0 |
mcall 5, PROBE_WAIT*100 |
xor esi, esi |
probe_loop: |
call random ; create a pseudo random number in eax (seeded by MAC) |
cmp al, PROBE_MIN*100 ; check if al is bigger then PROBE_MIN |
jae @f ; all ok |
add al, (PROBE_MAX-PROBE_MIN)*100 ; al is too small |
@@: |
cmp al, PROBE_MAX*100 |
jbe @f |
sub al, (PROBE_MAX-PROBE_MIN)*100 |
@@: |
movzx ebx,al |
DEBUGF 1,"Waiting %u0ms\n",ebx |
mcall 5 |
DEBUGF 1,"Sending Probe\n" |
mcall 76, API_ARP + 6 |
inc esi |
cmp esi, PROBE_NUM |
jb probe_loop |
; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned |
; IP within this time, we should create another adress, that have to be done later |
DEBUGF 1,"Waiting %us\n", ANNOUNCE_WAIT |
mcall 5, ANNOUNCE_WAIT*100 |
xor esi, esi |
announce_loop: |
DEBUGF 1,"Sending Announce\n" |
mcall 76, API_ARP + 6 |
inc esi |
cmp esi,ANNOUNCE_NUM |
je @f |
DEBUGF 1,"Waiting %us\n", ANNOUNCE_INTERVAL |
mcall 5, ANNOUNCE_INTERVAL*100 |
jmp announce_loop |
@@: |
error: |
DEBUGF 1,"Socket error\n" |
exit: ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;) |
mcall -1 |
random: ; Pseudo random actually |
mov eax, [generator] |
add eax, -43ab45b5h |
ror eax, 1 |
bswap eax |
xor eax, dword[MAC] |
ror eax, 1 |
xor eax, dword[MAC+2] |
mov [generator], eax |
ret |
; DATA AREA |
align 16 |
@IMPORT: |
library \ |
libini,'libini.obj' |
import libini, \ |
ini.get_str,'ini_get_str' |
include_debug_strings |
str_ip db 'ip', 0 |
str_subnet db 'subnet', 0 |
str_gateway db 'gateway', 0 |
str_dns db 'dns', 0 |
str_ipconfig db 'ipconfig', 0 |
str_type db 'type', 0 |
sockaddr1: |
dw AF_INET4 |
dw 68 shl 8 ; local port |
dd 0 ; local IP |
rb 10 |
sockaddr2: |
dw AF_INET4 |
dw 67 shl 8 ; destination port |
dd -1 ; destination IP |
rb 10 |
path db '/sys/network.ini' |
IM_END: |
inibuf rb 16 |
dhcpMsgType db ? |
dhcpLease dd ? |
dhcpServerIP dd ? |
dhcp: |
.ip dd ? |
.subnet dd ? |
.dns dd ? |
.gateway dd ? |
dhcpMsgLen dd ? |
socketNum dd ? |
MAC dp ? |
currTime dd ? |
generator dd ? |
dhcpMsg dd ? |
I_END: |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/zeroconf/dhcp.inc |
---|
0,0 → 1,263 |
;Name Number Length Meaning |
dhcp_pad_option equ 0 ; 0 None |
dhcp_end_option equ 255 ; 0 None |
dhcp_subnet_mask equ 1 ; 4 Subnet Mask Value |
dhcp_time_offset equ 2 ; 4 Time Offset in Seconds from UTC |
dhcp_router equ 3 ; N×4 Router addresses |
dhcp_time_server equ 4 ; N×4 Timeserver addresses |
dhcp_name_server equ 5 ; N×4 IEN-116 Server addresses |
dhcp_domain_server equ 6 ; N×4 DNS Server addresses |
dhcp_log_server equ 7 ; N×4 Logging Server addresses |
dhcp_quotes_server equ 8 ; N×4 Quotes Server addresses |
dhcp_lpr_server equ 9 ; N×4 Printer Server addresses |
dhcp_impress_server equ 10 ; N×4 Impress Server addresses |
dhcp_rlp_server equ 11 ; N×4 N RLP Server addresses |
dhcp_hostname equ 12 ; N Hostname string |
dhcp_boot_file_size equ 13 ; 2 Size of boot file in 512-octet blocks |
dhcp_merit_dump_file equ 14 ; N Client to dump and name the file to dump it to |
dhcp_domain_name equ 15 ; N The DNS domain name of the client |
dhcp_swap_server equ 16 ; 4 Swap Server address |
dhcp_root_path equ 17 ; N Path name for root disk |
dhcp_extension_file equ 18 ; N Path name for more BOOTP info |
;IP Layer Parameters per Host |
dhcp_forward equ 19 ; 1 Enable/Disable IP Forwarding |
dhcp_srcrte equ 20 ; 1 Enable/Disable Non-Local Source Routing |
dhcp_policy equ 21 ; N×8 Non-Local Source Routing Policy Filters |
dhcp_mag_dg_assembly equ 22 ; 2 Max Datagram Reassembly Size |
dhcp_default_ip_tll equ 23 ; 1 Default IP Time to Live |
dhcp_mtu_timeout equ 24 ; 4 Path MTU Aging Timeout |
dhcp_mtu_plateau equ 25 ; N×2 Path MTU Plateau Table |
;IP Layer Parameters per Interface |
dhcp_mtu_interface equ 26 ; 2 Interface MTU Size |
dhcp_mtu_subnet equ 27 ; 1 All Subnets are Local |
dhcp_broadcast_address equ 28 ; 4 Broadcast Address |
dhcp_mask_discovery equ 29 ; 1 Perform Mask Discovery |
dhcp_mask_supplier equ 30 ; 1 Provide Mask to Others |
dhcp_router_discovery equ 31 ; 1 Perform Router Discovery |
dhcp_router_request equ 32 ; 4 Router Solicitation Address |
dhcp_static_route equ 33 ; N×8 Static Routing Table |
;Link Layer Parameters per Interface |
dhcp_trailers equ 34 ; 1 Trailer Encapsulation |
dhcp_arp_timeout equ 35 ; 4 ARP Cache Timeout |
dhcp_ethernet equ 36 ; 1 Ethernet Encapsulation |
;TCP Parameters |
dhcp_default_tcp_tll equ 37 ; 1 Default TCP Time to Live |
dhcp_keepalive_time equ 38 ; 4 TCP Keepalive Interval |
dhcp_keepalive_data equ 39 ; 1 TCP Keepalive Garbage |
;Application and Service Parameters |
dhcp_nis_domain equ 40 ; N NIS Domain Name |
dhcp_nis_servers equ 41 ; N×4 NIS Server Addresses |
dhcp_ntp_servers equ 42 ; N×4 NTP Server Addresses |
dhcp_vendor_specific equ 43 ; N Vendor Specific Information |
dhcp_netbios_name_srv equ 44 ; N×4 NETBIOS Name Servers |
dhcp_netbios_dist_srv equ 45 ; N×4 NETBIOS Datagram Distribution |
dhcp_netbios_node_type equ 46 ; 1 NETBIOS Node Type |
dhcp_netbios_scope equ 47 ; N NETBIOS Scope |
dhcp_x_window_font equ 48 ; N×4 X Window Font Server |
dhcp_x_window_manager equ 49 ; N×4 X Window Display Manager |
dhcp_nis_domain_name equ 64 ; N NIS+ v3 Client Domain Name |
dhcp_nis_server_addr equ 65 ; N×4 NIS+ v3 Server Addresses |
dhcp_home_agent_addrs equ 68 ; N×4 Mobile IP Home Agent Addresses |
dhcp_smtp_server equ 69 ; N×4 Simple Mail Server Addresses |
dhcp_pop3_server equ 70 ; N×4 Post Office Server Addresses |
dhcp_nntp_server equ 71 ; N×4 Network News Server Addresses |
dhcp_www_server equ 72 ; N×4 WWW Server Addresses |
dhcp_finger_server equ 73 ; N×4 Finger Server Addresses |
dhcp_irc_server equ 74 ; N×4 Chat Server Addresses |
dhcp_streettalk_server equ 75 ; N×4 StreetTalk Server Addresses |
dhcp_stda_server equ 76 ; N×4 ST Directory Assist. Addresses |
;DHCP Extensions |
dhcp_address_request equ 50 ; 4 Requested IP Address |
dhcp_address_time equ 51 ; 4 IP Address Lease Time |
dhcp_option_overload equ 52 ; 1 Overload "sname" or "file" |
dhcp_msg_type equ 53 ; 1 DHCP Message Type |
dhcp_dhcp_server_id equ 54 ; 4 DHCP Server Identification |
dhcp_parameter_list equ 55 ; N Parameter Request List |
dhcp_dhcp_message equ 56 ; N DHCP Error Message |
dhcp_dhcp_max_msg_size equ 57 ; 2 DHCP Maximum Message Size |
dhcp_renewal_time equ 58 ; 4 DHCP Renewal (T1) Time |
dhcp_rebinding_time equ 59 ; 4 DHCP Rebinding (T2) Time |
dhcp_class_id equ 60 ; N Vendor Class Identifier |
dhcp_client_id equ 61 ; N Client Identifier |
dhcp_server_name equ 66 ; N TFTP Server Name |
dhcp_bootfile_name equ 67 ; N Boot File Name |
;Newer extensions |
dhcp_netware_ip_domain equ 62 ; N Netware/IP Domain Name |
dhcp_netware_ip_option equ 63 ; N Netware/IP sub Options |
dhcp_user_class equ 77 ; N User Class Information |
dhcp_directory_agent equ 78 ; N directory agent information |
dhcp_service_scope equ 79 ; N service location agent scope |
dhcp_rapid_commit equ 80 ; 0 Rapid Commit |
dhcp_client_fqdn equ 81 ; N Fully Qualified Domain Name |
dhcp_relay_agent_info equ 82 ; N Relay Agent Information, RFC 3046 |
dhcp_isns equ 83 ; N Internet Storage Name Service |
; 84 REMOVED/Unassigned |
dhcp_nds_servers equ 85 ; N Novell Directory Services |
dhcp_nds_tree_name equ 86 ; N Novell Directory Services |
dhcp_nds_conext equ 87 ; N Novell Directory Services |
dhcp_bcmcs equ 88 ; Controller Domain Name list |
dhcp_bcmcs equ 89 ; Controller IPv4 address option |
dhcp_authentication equ 90 ; N Authentication |
; 91 REMOVED/Unassigned |
; 92 REMOVED/Unassigned |
dhcp_client_system equ 93 ; N Client System Architecture |
dhcp_client_ndi equ 94 ; N Client Network Device Interface |
dhcp_ldap equ 95 ; N Lightweight Directory Access Protocol |
; 96 REMOVED/Unassigned |
dhcp_uuid_guid equ 97 ; N UUID/GUID-based Client Identifier |
dchp_user_auth equ 98 ; N Open Group's User Authentication |
; 99 REMOVED/Unassigned |
; 100 REMOVED/Unassigned |
; 101 REMOVED/Unassigned |
; 102 REMOVED/Unassigned |
; 103 REMOVED/Unassigned |
; 104 REMOVED/Unassigned |
; 105 REMOVED/Unassigned |
; 106 REMOVED/Unassigned |
; 107 REMOVED/Unassigned |
; 108 REMOVED/Unassigned |
; 109 REMOVED/Unassigned |
; 110 REMOVED/Unassigned |
; 111 REMOVED/Unassigned |
dhcp_netinfo_address equ 112 ; N NetInfo Parent Server Address |
dhcp_netinfo_tag equ 113 ; N NetInfo Parent Server Tag |
dhcp_url equ 114 ; N URL |
; 115 REMOVED/Unassigned |
dhcp_auto_config equ 116 ; N DHCP Auto-Configuration |
dhcp_ns_search equ 117 ; N Name Service Search |
dhcp_subnet_selection equ 118 ; 4 Subnet Selection Option |
dhcp_domain_search equ 119 ; N DNS domain search list |
dhcp_sip_servers equ 120 ; N SIP Servers DHCP Option |
dhcp_cl_static_route equ 121 ; N Classless Static Route Option |
dhcp_ccc equ 122 ; N CableLabs Client Configuration |
dhcp_geoconf equ 123 ; 16 GeoConf Option |
dhcp_v_i_vendor_class equ 124 ; Vendor-Identifying Vendor Class |
dhcp_v_i_vendor_spec equ 125 ; Vendor-Identifying Vendor-Specific |
; 126 REMOVED/Unassigned |
; 127 REMOVED/Unassigned |
dhcp_pxe equ 128 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_etherboot_sign equ 128 ; Etherboot signature. 6 bytes: E4:45:74:68:00:00 |
dhcp_docsis equ 128 ; DOCSIS "full security" server IP address |
dhcp_tftp_server_ip equ 128 ; TFTP Server IP address (for IP Phone software load) |
dhcp_pxe equ 129 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_kernel_options equ 129 ; Kernel options. Variable length string |
dhcp_call_server_ip equ 129 ; Call Server IP address |
dhcp_pxe equ 130 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_ethernet_interface equ 130 ; Ethernet interface. Variable length string. |
dhcp_siscrimination equ 130 ; Discrimination string (to identify vendor) |
dhcp_pxe equ 131 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_remote_stat_server equ 131 ; Remote statistics server IP address |
dhcp_pxe equ 132 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_802.1p equ 132 ; 802.1P VLAN ID |
dhcp_pxe equ 133 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_802.1q equ 133 ; 802.1Q L2 Priority |
dhcp_pxe equ 134 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_diffserv equ 134 ; Diffserv Code Point |
dhcp_pxe equ 135 ; PXE - undefined (vendor specific) (Tentatively Assigned - 23 June 2005) |
dhcp_http_proxy_psa equ 135 ; HTTP Proxy for phone-specific applications |
; 136 REMOVED/Unassigned |
; 137 REMOVED/Unassigned |
; 138 REMOVED/Unassigned |
; 139 REMOVED/Unassigned |
; 140 REMOVED/Unassigned |
; 141 REMOVED/Unassigned |
; 142 REMOVED/Unassigned |
; 143 REMOVED/Unassigned |
; 144 REMOVED/Unassigned |
; 145 REMOVED/Unassigned |
; 146 REMOVED/Unassigned |
; 147 REMOVED/Unassigned |
; 148 REMOVED/Unassigned |
; 149 REMOVED/Unassigned |
dhcp_tftp_server_addr equ 150 ; TFTP server address (Tentatively Assigned - 23 June 2005) |
dhcp_etherboot equ 150 ; Etherboot |
dhcp_grub_conf_path equ 150 ; GRUB configuration path name |
; 151 REMOVED/Unassigned |
; 152 REMOVED/Unassigned |
; 153 REMOVED/Unassigned |
; 154 REMOVED/Unassigned |
; 155 REMOVED/Unassigned |
; 156 REMOVED/Unassigned |
; 157 REMOVED/Unassigned |
; 158 REMOVED/Unassigned |
; 159 REMOVED/Unassigned |
; 160 REMOVED/Unassigned |
; 161 REMOVED/Unassigned |
; 162 REMOVED/Unassigned |
; 163 REMOVED/Unassigned |
; 164 REMOVED/Unassigned |
; 165 REMOVED/Unassigned |
; 166 REMOVED/Unassigned |
; 167 REMOVED/Unassigned |
; 168 REMOVED/Unassigned |
; 169 REMOVED/Unassigned |
; 170 REMOVED/Unassigned |
; 171 REMOVED/Unassigned |
; 172 REMOVED/Unassigned |
; 173 REMOVED/Unassigned |
; 174 REMOVED/Unassigned |
dhcp_etherboot equ 175 ; Etherboot (Tentatively Assigned - 23 June 2005) |
dhcp_ip_telephone equ 176 ; IP Telephone (Tentatively Assigned - 23 June 2005) |
dhcp_etherboot equ 177 ; Etherboot (Tentatively Assigned - 23 June 2005) |
dhcp_packetcable equ 177 ; PacketCable and CableHome (replaced by 122) |
; 178 REMOVED/Unassigned |
; 179 REMOVED/Unassigned |
; 180 REMOVED/Unassigned |
; 181 REMOVED/Unassigned |
; 182 REMOVED/Unassigned |
; 183 REMOVED/Unassigned |
; 184 REMOVED/Unassigned |
; 185 REMOVED/Unassigned |
; 186 REMOVED/Unassigned |
; 187 REMOVED/Unassigned |
; 188 REMOVED/Unassigned |
; 189 REMOVED/Unassigned |
; 190 REMOVED/Unassigned |
; 191 REMOVED/Unassigned |
; 192 REMOVED/Unassigned |
; 193 REMOVED/Unassigned |
; 194 REMOVED/Unassigned |
; 195 REMOVED/Unassigned |
; 196 REMOVED/Unassigned |
; 197 REMOVED/Unassigned |
; 198 REMOVED/Unassigned |
; 199 REMOVED/Unassigned |
; 200 REMOVED/Unassigned |
; 201 REMOVED/Unassigned |
; 202 REMOVED/Unassigned |
; 203 REMOVED/Unassigned |
; 204 REMOVED/Unassigned |
; 205 REMOVED/Unassigned |
; 206 REMOVED/Unassigned |
; 207 REMOVED/Unassigned |
dhcp_pxelinux.magic equ 208 ; pxelinux.magic (string) = F1:00:74:7E (241.0.116.126) (Tentatively Assigned - 23 June 2005) |
dhcp_pxelinux.conffile equ 209 ; pxelinux.configfile (text) (Tentatively Assigned - 23 June 2005) |
dhcp_pxelinux.path equ 210 ; pxelinux.pathprefix (text) (Tentatively Assigned - 23 June 2005) |
dhcp_pxelinux.reboot equ 211 ; pxelinux.reboottime (unsigned integer 32 bits) (Tentatively Assigned - 23 June 2005) |
; 212 REMOVED/Unassigned |
; 213 REMOVED/Unassigned |
; 214 REMOVED/Unassigned |
; 215 REMOVED/Unassigned |
; 216 REMOVED/Unassigned |
; 217 REMOVED/Unassigned |
; 218 REMOVED/Unassigned |
; 219 REMOVED/Unassigned |
dhcp_subnet_aloc equ 220 ; Subnet Allocation Option (Tentatively Assigned - 23 June 2005) |
dhcp_virtual_subnet equ 221 ; Virtual Subnet Selection Option (Tentatively Assigned - 23 June 2005) |
; 222 REMOVED/Unassigned |
; 223 REMOVED/Unassigned |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/netcfg/vendors.inc |
---|
0,0 → 1,1072 |
; AUTHOR: Victor Alberto Gil Hancco Laquita <vhanla@gmail.com> |
; This list might content mistakes, plz report it |
; There are 865 Lists of Vendors' Names |
; Date: 8/14/2005 |
; |
; maybe this list is outdated... |
; (the source was from 2004 list) |
; changed 11/05/2006: + 3 vendors and no more label 'PREVIOUSVERSIONLIST' |
; so the total quantity of vendors is 875 now (changes by Sergey Kuzmin) |
; changed 16/08/2006: + 122 vendors |
; so the total quantity of vendors is 987 now (changes by Sergey Kuzmin) |
; changed ??/04/2007: |
; size optimezed |
; total quantity of vendors is 997 now (changes by Mihailov Ilia) |
macro VendorID a,b { ; by mike.dld |
dw a |
dd _vtmp#a |
\iglobal |
_vtmp#a db b |
db 0 |
\};endg |
} |
macro ClassID a,b,c,d { |
db a |
db b |
local tt |
if c eq |
db 0 |
db 1 |
tt = 'x' |
else |
db c |
db 0 |
tt = c |
end if |
dd _ctmp#a#b#tt |
\iglobal |
_ctmp#a#b#tt db d |
db 0 |
\};endg |
} |
;-------------------------------------- |
VendorsTab: |
VendorID 0x0033, 'PARADYNE CORP.' |
VendorID 0x003D, 'Lockheed Martin Corp' |
VendorID 0x0100, 'NCIPHER CORP. LTD' |
VendorID 0x0675, 'DYNALINK' |
VendorID 0x0571, 'BERKOM' |
VendorID 0x0A89, 'BREA TECHNOLOGIES INC' |
VendorID 0x0E11, 'COMPAQ COMPUTER CORP.' |
VendorID 0x1000, 'SYMBIOS LOGIC INC/LSI Logic' |
VendorID 0x1001, 'KOLTER ELECTRONIC' |
VendorID 0x1002, 'ATI TECHNOLOGIES INC' |
VendorID 0x1003, 'ULSI' |
VendorID 0x1004, 'VLSI TECHNOLOGY INC' |
VendorID 0x1005, 'ADL' |
VendorID 0x100B, 'NATIONAL SEMICONDUCTOR CORPORATION' |
VendorID 0x100C, 'Tseng Labs' |
VendorID 0x100E, 'Weitek' |
VendorID 0x1010, 'VIDEO LOGIC LTD' |
VendorID 0x1011, 'Digital Equipment Corporation' |
VendorID 0x1013, 'Cirrus Logic' |
VendorID 0x1014, 'IBM' |
VendorID 0x1017, 'Spea Software AG' |
VendorID 0x1018, 'UNISYS CORPORATION' |
VendorID 0x1019, 'ELITEGROUP COMPUTER SYS' |
VendorID 0x101A, 'NCR Corporation' |
VendorID 0x101E, 'AMERICAN MEGATRENDS' |
VendorID 0x1020, 'HITACHI COMPUTER PRODUCTS' |
VendorID 0x1021, 'OKI ELECTRIC INDUSTRY CO. LTD.' |
VendorID 0x1022, 'Advanced Micro Devices' |
VendorID 0x1023, 'TRIDENT MICROSYSTEMS' |
VendorID 0x1025, 'Acer Incorporated' |
VendorID 0x1028, 'DELL COMPUTER CORPORATION' |
VendorID 0x102A, 'LSI LOGIC CORPORATION' |
VendorID 0x102B, 'MATROX GRAPHICS' |
VendorID 0x102C, 'Asiliant (Chips And Technologies)' |
VendorID 0x102D, 'Wyse Technologies' |
VendorID 0x102F, 'TOSHIBA AMERICA' |
VendorID 0x1031, 'miro Computer Products AG' |
VendorID 0x1033, 'NEC CORPORATION' |
VendorID 0x1036, 'Future Domain' |
VendorID 0x1038, 'AMP' |
VendorID 0x1039, 'SILICON INTEGRATED SYSTEMS' |
VendorID 0x103C, 'Hewlett-Packard Company' |
VendorID 0x103F, 'SYNOPSYS/LOGIC MODELING GROUP' |
VendorID 0x1042, 'Micron Electronics' |
VendorID 0x1043, 'ASUSTEK COMPUTER' |
VendorID 0x1044, 'DISTRIBUTED PROCESSING TECHNOLOGY' |
VendorID 0x1045, 'OPTI INC.' |
VendorID 0x1048, 'ELSA AG' |
VendorID 0x1049, 'FOUNTAIN TECHNOLOGIES' |
VendorID 0x104A, 'STMicroelectronics' |
VendorID 0x104B, 'BusLogic' |
VendorID 0x104C, 'TEXAS INSTRUMENTS' |
VendorID 0x104D, 'SONY CORPORATION' |
VendorID 0x104E, 'Oak Technology' |
VendorID 0x104F, 'Co-Time Computer Ltd.' |
VendorID 0x1050, 'WINBOND ELECTRONICS CORP' |
VendorID 0x1051, 'Anigma Corp.' |
VendorID 0x1054, 'HITACHI' |
VendorID 0x1055, 'Standard Microsystems Corp.' |
VendorID 0x1057, 'Motorola' |
VendorID 0x1058, 'ETRI' |
VendorID 0x1059, 'TEKNOR INDUSTRIAL COMPUTERS INC' |
VendorID 0x105A, 'PROMISE TECHNOLOGY' |
VendorID 0x105B, 'FOXCONN INTERNATIONAL INC' |
VendorID 0x105D, 'NUMBER 9 VISUAL TECHNOLOGY' |
VendorID 0x105F, 'INFOTRONIC AMERICA INC' |
VendorID 0x1060, 'United Microelectronics' |
VendorID 0x1061, '8x8 Inc.' |
VendorID 0x1063, 'OCEAN MANUFACTURING LTD' |
VendorID 0x1064, 'ALCATEL' |
VendorID 0x1065, 'Texas Microsystems' |
VendorID 0x1066, 'Picopower Technology' |
VendorID 0x1067, 'MITSUBISHI ELECTRIC AMERICA' |
VendorID 0x1068, 'DIVERSIFIED TECHNOLOGY' |
VendorID 0x1069, 'MYLEX CORPORATION' |
VendorID 0x106B, 'APPLE COMPUTER INC.' |
VendorID 0x106C, 'Hyundai Electronics America' |
VendorID 0x106D, 'SEQUENT COMPUTER SYSTEMS' |
VendorID 0x1070, 'DAEWOO TELECOM LTD' |
VendorID 0x1071, 'MITAC' |
VendorID 0x1073, 'YAMAHA CORPORATION' |
VendorID 0x1074, 'Nexgen Microsystems' |
VendorID 0x1076, 'Chaintech Comp.' |
VendorID 0x1077, 'QLOGIC Corporation' |
VendorID 0x1078, 'Cyrix Corporation' |
VendorID 0x1079, 'I-BUS' |
VendorID 0x107B, 'GATEWAY 2000' |
VendorID 0x107D, 'Leadtek Research' |
VendorID 0x107E, 'INTERPHASE CORPORATION' |
VendorID 0x107F, 'Data Technology Corporation' |
VendorID 0x1080, 'Cypress Semiconductor' |
VendorID 0x1081, 'Radius Inc.' |
VendorID 0x1083, 'Forex Computer Corporation' |
VendorID 0x1085, 'Tulip Computers International BV' |
VendorID 0x1087, 'Cache Computer' |
VendorID 0x108A, 'SBS Operations' |
VendorID 0x108D, 'OLICOM' |
VendorID 0x108E, 'Sun Microsystems' |
VendorID 0x1091, 'Intergraph Corporation' |
VendorID 0x1092, 'Diamond Computer Systems' |
VendorID 0x1093, 'National Instruments' |
VendorID 0x1095, 'SILICON IMAGE (WAS CMD TECHNOLOGY INC)' |
VendorID 0x1096, 'ALACRON' |
VendorID 0x1097, 'APPIAN Graphics/ETMA' |
VendorID 0x1098, 'Quantum Designs Ltd.' |
VendorID 0x109A, 'PACKARD BELL NEC' |
VendorID 0x109E, 'BROOKTREE CORPORATION' |
VendorID 0x109F, 'TRIGEM COMPUTER INC.' |
VendorID 0x10A0, 'MEIDENSHA CORPORATION' |
VendorID 0x10A2, 'QUANTUM EFFECT DESIGN' |
VendorID 0x10A4, 'Globe Manufacturing Sales' |
VendorID 0x10A8, 'Sierra Semiconductor' |
VendorID 0x10A9, 'SILICON GRAPHICS' |
VendorID 0x10AC, 'HONEYWELL IAC' |
VendorID 0x10AD, 'Winbond Systems Labs' |
VendorID 0x10AF, 'MICRO COMPUTER SYSTEMS INC' |
VendorID 0x10B5, 'PLX TECHNOLOGY.' |
VendorID 0x10B6, 'MADGE NETWORKS' |
VendorID 0x10B7, '3COM Corp, Networking Division' |
VendorID 0x10B8, 'Standard Microsystems Corporation' |
VendorID 0x10B9, 'ACER LABS Incorp.' |
VendorID 0x10BA, 'MITSUBISHI ELECTRIC CORP.' |
VendorID 0x10BD, 'Surecom Technology' |
VendorID 0x10C2, 'AUSPEX SYSTEMS INC.' |
VendorID 0x10C3, 'Samsung Semiconductors' |
VendorID 0x10C4, 'Award Software International Inc.' |
VendorID 0x10C8, 'NEOMAGIC CORPORATION' |
VendorID 0x10CA, 'FUJITSU MICROELECTRONIC' |
VendorID 0x10CB, 'OMRON CORPORATION' |
VendorID 0x10CD, 'ADVANCED SYSTEM PRODUCTS' |
VendorID 0x10CF, 'FUJITSU LIMITED' |
VendorID 0x10D1, 'FUTUREPLUS SYSTEMS CORP.' |
VendorID 0x10D2, 'MOLEX INCORPORATED' |
VendorID 0x10D9, 'Macronix International Co. Ltd.' |
VendorID 0x10DB, 'ROHM LSI SYSTEMS' |
VendorID 0x10DC, 'CERN-European Lab. for Particle Physics' |
VendorID 0x10DD, 'EVANS & SUTHERLAND' |
VendorID 0x10DE, 'NVIDIA CORPORATION' |
VendorID 0x10DF, 'EMULEX CORPORATION' |
VendorID 0x10E1, 'TEKRAM TECHNOLOGY CO.LTD.' |
VendorID 0x10E3, 'TUNDRA SEMICONDUCTOR CORP' |
VendorID 0x10E5, 'MICRO INDUSTRIES CORPORATION' |
VendorID 0x10E8, 'Applied Micro Circuits Corp.' |
VendorID 0x10EA, 'Tvia, Inc.' |
VendorID 0x10EB, 'Artist Graphics' |
VendorID 0x10EC, 'REALTEK SEMICONDUCTOR CORP.' |
VendorID 0x10ED, 'Ascii Corporation' |
VendorID 0x10EE, 'XILINX' |
VendorID 0x10EF, 'Racore Computer Products' |
VendorID 0x10F0, 'Curtiss-Wright Controls Embedded Computing' |
VendorID 0x10F1, 'TYAN COMPUTER' |
VendorID 0x10F4, 'S-Mos Systems' |
VendorID 0x10F5, 'NKK CORPORATION' |
VendorID 0x10F6, 'Creative Electronic Systems SA' |
VendorID 0x10FA, 'Truevision' |
VendorID 0x10FB, 'Thesys Microelectronics' |
VendorID 0x10FC, 'I-O DATA DEVICE' |
VendorID 0x10FE, 'FAST MULTIMEDIA AG' |
VendorID 0x1101, 'INITIO CORPORATION' |
VendorID 0x1102, 'Creative Labs' |
VendorID 0x1105, 'SIGMA DESIGNS' |
VendorID 0x1106, 'VIA TECHNOLOGIES' |
VendorID 0x1107, 'ASCEND COMMUNICATIONS/Stratus Computer' |
VendorID 0x1108, 'Proteon Inc.' |
VendorID 0x1109, 'Adaptec/Cogent Data Technologies Inc' |
VendorID 0x110A, 'SIEMENS PC SYSTEME GMBH' |
VendorID 0x110B, 'Chromatic Research Inc' |
VendorID 0x1111, 'SANTA CRUZ OPERATION' |
VendorID 0x1112, 'Osicom Technologies Inc.' |
VendorID 0x1113, 'ACCTON TECHNOLOGY' |
VendorID 0x1114, 'Atmel Corp.' |
VendorID 0x1116, 'Media 100, Inc.' |
VendorID 0x1117, 'Datacube Inc.' |
VendorID 0x1118, 'FCI ELECTRONICS' |
VendorID 0x1119, 'ICP-VORTEX COMPUTERSYSTEM GMBH' |
VendorID 0x111A, 'EFFICIENT NETWORKS' |
VendorID 0x111C, 'Tricord Systems Inc.' |
VendorID 0x111D, 'INTEGRATED DEVICE TECH' |
VendorID 0x111F, 'Precision Digital Images' |
VendorID 0x1120, 'EMC CORPORATION' |
VendorID 0x1127, 'FORE SYSTEMS INC' |
VendorID 0x112A, 'HERMES ELECTRONICS COMPANY' |
VendorID 0x112E, 'Infomedia' |
VendorID 0x112F, 'IMAGING TECHNOLOGY' |
VendorID 0x1131, 'PHILIPS SEMICONDUCTORS' |
VendorID 0x1132, 'MITEL CORP' |
VendorID 0x1133, 'Eicon Networks Corporation' |
VendorID 0x1134, 'MERCURY COMPUTER SYSTEMS' |
VendorID 0x1135, 'FUJI XEROX CO LTD' |
VendorID 0x1136, 'MOMENTUM DATA SYSTEMS' |
VendorID 0x1137, 'CISCO SYSTEMS INC' |
VendorID 0x1138, 'ZIATECH CORPORATION' |
VendorID 0x113C, 'CYCLONE MICROSYSTEMS.' |
VendorID 0x113E, 'SANYO ELECTRIC CO-Information Systems Division' |
VendorID 0x113F, 'Equinox Systems' |
VendorID 0x1141, 'CREST MICROSYSTEM INC.' |
VendorID 0x1142, 'Alliance Semiconductor CA - USA' |
VendorID 0x1144, 'Cincinnati Milacron' |
VendorID 0x1145, 'WORKBIT CORPORATION' |
VendorID 0x1146, 'FORCE COMPUTERS GMBH' |
VendorID 0x1147, 'Interface Corp' |
VendorID 0x1148, 'SYSKONNECT/Marvell' |
VendorID 0x114A, 'VMIC' |
VendorID 0x114C, 'ANNABOOKS' |
VendorID 0x114F, 'DIGI INTERNATIONAL' |
VendorID 0x1154, 'MELCO INC' |
VendorID 0x1155, 'Pine Technology Ltd' |
VendorID 0x1158, 'Voarx R&D Inc' |
VendorID 0x1159, 'Mutech' |
VendorID 0x115C, 'PHOTRON LTD.' |
VendorID 0x115D, 'XIRCOM' |
VendorID 0x1161, 'PFU LIMITED' |
VendorID 0x1163, 'RENDITION' |
VendorID 0x1165, 'Imagraph Corporation' |
VendorID 0x1166, 'Reliance Computer Corp./ServerWorks' |
VendorID 0x1169, 'Centre f/Dev. of Adv. Computing' |
VendorID 0x116A, 'Polaris Communications' |
VendorID 0x116E, 'ELECTRONICS FOR IMAGING' |
VendorID 0x1170, 'INVENTEC CORPORATION' |
VendorID 0x1171, 'BLUE WAVE SYSTEMS' |
VendorID 0x1172, 'ALTERA CORPORATION' |
VendorID 0x1176, 'SBE' |
VendorID 0x1178, 'Alfa Inc' |
VendorID 0x1179, 'TOSHIBA AMERICA INFO SYSTEMS' |
VendorID 0x117B, 'GCE-8320B' |
VendorID 0x117E, 'T/R Systems' |
VendorID 0x1180, 'RICOH CO LTD' |
VendorID 0x1185, 'Dataworld' |
VendorID 0x1186, 'D-LINK SYSTEM INC' |
VendorID 0x1187, 'ADVANCED TECHNOLOGY LABORATORIES' |
VendorID 0x1189, 'MATSUSHITA ELECTIC INDUSTRIAL CO LTD' |
VendorID 0x118B, 'PLATYPUS TECHNOLOGY PTY LTD' |
VendorID 0x118C, 'Corollary Inc' |
VendorID 0x118D, 'BitFlow Inc' |
VendorID 0x118E, 'Hermstedt AG' |
VendorID 0x1190, 'Tripace' |
VendorID 0x1191, 'ACARD TECHNOLOGY' |
VendorID 0x1193, 'ZeitNet' |
VendorID 0x1195, 'RATOC SYSTEMS INC' |
VendorID 0x1197, 'Gage Applied Technologies' |
VendorID 0x1199, 'Attachmate Corp.' |
VendorID 0x119A, 'MINDSHARE.' |
VendorID 0x119B, 'Omega Micro Inc.' |
VendorID 0x119D, 'BUG.' |
VendorID 0x119E, 'FUJITSU MICROELECTRONICS LTD.' |
VendorID 0x119F, 'BULL HN INFORMATION SYSTEMS' |
VendorID 0x11A1, 'HAMAMATSU PHOTONICS K.K.' |
VendorID 0x11A8, 'Systech Corp.' |
VendorID 0x11A9, 'InnoSys Inc.' |
VendorID 0x11AA, 'ACTEL' |
VendorID 0x11AB, 'GALILEO TECHNOLOGY LTD/Marvell Semiconductor, Inc.' |
VendorID 0x11AD, 'LITE-ON COMMUNICATIONS INC' |
VendorID 0x11AE, 'SCITEX CORPORATION' |
VendorID 0x11AF, 'AVID TECHNOLOGY INC' |
VendorID 0x11B0, 'V3 SEMICONDUCTOR INC./Quicklogic Corp' |
VendorID 0x11B2, 'EASTMAN KODAK' |
VendorID 0x11B3, 'BARR SYSTEMS INC.' |
VendorID 0x11B5, 'Radstone Technology Ltd.' |
VendorID 0x11B8, 'Xpoint Technologies Inc' |
VendorID 0x11B9, 'Pathlight Technology Inc.' |
VendorID 0x11BC, 'Network Peripherals Inc' |
VendorID 0x11BD, 'Pinnacle Systems Inc.' |
VendorID 0x11BF, 'ASTRODESIGN' |
VendorID 0x11C1, 'AGERE/LUCENT' |
VendorID 0x11C6, 'DAINIPPON SCREEN MFG. CO. LTD' |
VendorID 0x11C8, 'DOLPHIN INTERCONNECT SOLUTIONS AS' |
VendorID 0x11C9, 'MAGMA' |
VendorID 0x11CA, 'LSI SYSTEMS' |
VendorID 0x11CB, 'SPECIALIX INTERNATIONAL LTD' |
VendorID 0x11CE, 'NETACCESS/Primary Rate Inc' |
VendorID 0x11D0, 'LOCKHEED MARTIN-Electronics & Communications' |
VendorID 0x11D1, 'AuraVision Corporation' |
VendorID 0x11D2, 'INTERCOM INC.' |
VendorID 0x11D4, 'Analog Devices, Inc.' |
VendorID 0x11D5, 'IKON CORPORATION/Tahoma Technology' |
VendorID 0x11D9, 'TOSHIBA TEC CORPORATION' |
VendorID 0x11DA, 'NOVELL' |
VendorID 0x11DB, 'Sega Enterprises Ltd' |
VendorID 0x11DE, 'Zoran Corporation' |
VendorID 0x11DF, 'NEW WAVE PDG' |
VendorID 0x11E3, 'QUICKLOGIC CORPORATION' |
VendorID 0x11EC, 'CORECO INC' |
VendorID 0x11EE, 'DOME IMAGING SYSTEMS INC' |
VendorID 0x11F0, 'Compu-Shack GmbH' |
VendorID 0x11F4, 'Kinetic Systems Corporation' |
VendorID 0x11F6, 'Powermatic Data Systems Ltd' |
VendorID 0x11F8, 'PMC-SIERRA INC' |
VendorID 0x11FE, 'Comtrol Corp' |
VendorID 0x1202, 'Network General Corp' |
VendorID 0x1203, 'AGFA CORPORATION' |
VendorID 0x1206, 'AMDAHL CORPORATION' |
VendorID 0x1208, 'Parsytec GmbH' |
VendorID 0x1209, 'Sci Systems Inc' |
VendorID 0x120E, 'Cyclades Corporation' |
VendorID 0x120F, 'ESSENTIAL COMMUNICATIONS' |
VendorID 0x1214, 'PERFORMANCE TECHNOLOGIES.' |
VendorID 0x1216, 'PURUP-EskoFot A/S' |
VendorID 0x1217, 'O2MICRO.' |
VendorID 0x121A, '3DFX INTERACTIVE' |
VendorID 0x121B, 'VIRATA LTD' |
VendorID 0x1220, 'Ariel Corporation' |
VendorID 0x1221, 'CONTEC CO. LTD' |
VendorID 0x1223, 'ARTESYN COMMUNICATIONS PRODUCTS INC' |
VendorID 0x1224, 'Interactive Images' |
VendorID 0x1227, 'TECH-SOURCE' |
VendorID 0x122C, 'SICAN GMBH' |
VendorID 0x122D, 'Aztech System Ltd' |
VendorID 0x1232, 'MARCONI COMMUNICATIONS LTD' |
VendorID 0x1236, 'Sigma Designs, Inc' |
VendorID 0x124C, 'Solitron Technologies Inc.' |
VendorID 0x124D, 'Stallion Technologies' |
VendorID 0x124F, 'Infortrend Technology Inc' |
VendorID 0x1256, 'Perceptive Solutions Inc.' |
VendorID 0x1258, 'Gilbarco Inc.' |
VendorID 0x125B, 'Asix Electronics Corp.' |
VendorID 0x1266, 'Microdyne Corp.' |
VendorID 0x1267, 'S.A. Telecommunications' |
VendorID 0x1361, 'SOLITON SYSTEMS K.K.' |
VendorID 0x123C, 'CENTURY SYSTEMS.' |
VendorID 0x123D, 'Engineering Design Team Inc.' |
VendorID 0x123F, 'C-CUBE MICROSYSTEMS' |
VendorID 0x1242, 'JAYCOR NETWORKS INC./JNI Corporation' |
VendorID 0x1244, 'AVM AUDIOVISUELLES MKTG & COMPUTER SYSTEM GMBH' |
VendorID 0x124B, 'SBS TECHNOLOGIES' |
VendorID 0x1250, 'Hitachi Microcomputer System Ltd.' |
VendorID 0x1253, 'GUZIK TECHNICAL ENTERPRISES' |
VendorID 0x1255, 'OPTIBASE LTD' |
VendorID 0x1259, 'ALLIED TELESYN INTERNATIONAL' |
VendorID 0x125C, 'AURORA TECHNOLOGIES.' |
VendorID 0x125D, 'ESS TECHNOLOGY, INC.' |
VendorID 0x125F, 'CONCURRENT TECHNOLOGIES' |
VendorID 0x1260, 'INTERSIL CORP' |
VendorID 0x1261, 'MATSUSHITA-KOTOBUKI ELECTRONICS' |
VendorID 0x1264, 'AVAL NAGASAKI CORPORATION' |
VendorID 0x1268, 'TEKTRONIX' |
VendorID 0x126C, 'Nortel Networks Corp.' |
VendorID 0x126D, 'SPLASH TECHNOLOGY.' |
VendorID 0x126E, 'SUMITOMO METAL INDUSTRIES' |
VendorID 0x126F, 'SILICON MOTION.' |
VendorID 0x1270, 'OLYMPUS OPTICAL CO. LTD.' |
VendorID 0x1274, 'Creative Labs (was Ensoniq, Malvern)' |
VendorID 0x1275, 'NETWORK APPLIANCE CORPORATION' |
VendorID 0x1278, 'Transtech Parallel Systems' |
VendorID 0x1279, 'TRANSMETA CORPORATION' |
VendorID 0x127A, 'CONEXANT, ROCKWELL' |
VendorID 0x127D, 'VELA RESEARCH LP' |
VendorID 0x127F, 'FUJIFILM' |
VendorID 0x1281, 'YOKOGAWA ELECTRIC CORPORATION' |
VendorID 0x1283, 'Integrated Technology Express Inc.' |
VendorID 0x1286, 'MAZET GMBH' |
VendorID 0x128B, 'TRANSWITCH CORPORATION' |
VendorID 0x128D, 'G2 Networks Inc.' |
VendorID 0x128F, 'TATENO DENNOU.' |
VendorID 0x1290, 'TOSHIBA PERSONAL COMPUTER SYSTEM CORP.' |
VendorID 0x1291, 'NCS COMPUTER ITALIA SRL' |
VendorID 0x1292, 'TRITECH MICROELECTRONICS INC' |
VendorID 0x1297, 'SHUTTLE COMPUTER' |
VendorID 0x1299, 'KNOWLEDGE TECHNOLOGY LAB.' |
VendorID 0x129A, 'VMETRO Inc.' |
VendorID 0x129E, 'VICTOR COMPANY OF JAPAN' |
VendorID 0x12A0, 'ALLEN- BRADLEY COMPANY' |
VendorID 0x12A3, 'Lucent Technologies AMR' |
VendorID 0x12A7, 'AMO GMBH' |
VendorID 0x12A9, 'XIOTECH CORPORATION' |
VendorID 0x12AB, 'YUAN YUAN ENTERPRISE CO. LTD.' |
VendorID 0x12AE, 'Alteon Networks Inc.' |
VendorID 0x12B6, 'NATURAL MICROSYSTEMS' |
VendorID 0x12B7, 'COGNEX MODULAR VISION SYSTEMS DIV.-ACUMEN INC.' |
VendorID 0x12B9, '3Com Corp, Modem Division' |
VendorID 0x12BC, 'ARRAY MICROSYSTEMS' |
VendorID 0x12BE, 'ANCHOR CHIPS INC.' |
VendorID 0x12BF, 'Fujifilm Microdevices' |
VendorID 0x12C0, 'INFIMED' |
VendorID 0x12C3, 'Holtek Microelectronics Inc.' |
VendorID 0x12C4, 'Connect Tech Inc' |
VendorID 0x12C6, 'Mitan Corporation' |
VendorID 0x12C7, 'Dialogic Corp' |
VendorID 0x12CA, 'Integrated Computing Engines' |
VendorID 0x12CD, 'Aims Lab' |
VendorID 0x12D2, 'NVIDIA (WAS: STB,SGS THOMPSON)' |
VendorID 0x12D3, 'GE VINGMED ULTRASOUND AS' |
VendorID 0x12D4, 'COMVERSE NETWORKS SYSTEM & Ulticom, Inc.' |
VendorID 0x12D5, 'Equator Technologies' |
VendorID 0x12D6, 'Analogic Corp' |
VendorID 0x12D8, 'PERICOM SEMICONDUCTOR' |
VendorID 0x12D9, 'Aculab PLC' |
VendorID 0x12DA, 'True Time Inc.' |
VendorID 0x12DE, 'Rainbow Technologies' |
VendorID 0x12DF, 'SBS Technologies Inc' |
VendorID 0x12E0, 'Chase Research PLC' |
VendorID 0x12E2, 'Datum Inc. Bancomm-Timing Division' |
VendorID 0x12E4, 'Brooktrout Technology Inc' |
VendorID 0x12E7, 'Sebring Systems' |
VendorID 0x12EA, 'Real Vision' |
VendorID 0x12EB, 'Aureal Semiconductor' |
VendorID 0x12EC, '3A' |
VendorID 0x12F0, 'PENTEK' |
VendorID 0x12F7, 'COGNEX INC.' |
VendorID 0x12FB, 'Spectrum Signal Processing' |
VendorID 0x12FC, 'CAPITAL EQUIPMENT CORP' |
VendorID 0x12FE, 'ESD Electronic System Design GmbH' |
VendorID 0x1304, 'Juniper Networks Inc.' |
VendorID 0x1307, 'Computer Boards' |
VendorID 0x1308, 'LEVEL ONE COMMUNICATIONS/Jato Technologies Inc.' |
VendorID 0x130A, 'Mitsubishi Electric MicroComputer' |
VendorID 0x130B, 'Colorgraphic Communications Corp' |
VendorID 0x130F, 'Advanet Inc' |
VendorID 0x1310, 'GESPAC' |
VendorID 0x1313, 'YASKAWA ELECTRIC CO.' |
VendorID 0x1316, 'TERADYNE INC.' |
VendorID 0x1317, 'ADMTEK INC' |
VendorID 0x1318, 'Packet Engines Inc.' |
VendorID 0x1319, 'ForteMedia' |
VendorID 0x131F, 'SIIG Inc' |
VendorID 0x1325, 'SALIX TECHNOLOGIES INC' |
VendorID 0x1326, 'SeaChange International' |
VendorID 0x1331, 'RadiSys Corp.' |
VendorID 0x133D, 'PRISA NETWORKS' |
VendorID 0x133F, 'SCM MICROSYSTEMS' |
VendorID 0x1342, 'PROMAX SYSTEMS INC' |
VendorID 0x1344, 'MICRON TECHNOLOGY INC' |
VendorID 0x134A, 'Domex' |
VendorID 0x134B, 'ARK RESEARCH CORP.' |
VendorID 0x134C, 'CHORI JOHO SYSTEM CO. LTD' |
VendorID 0x134D, 'PC-TEL INC' |
VendorID 0x135A, 'BRAIN BOXES LIMITED' |
VendorID 0x135C, 'QUATECH INC' |
VendorID 0x135E, 'SEALEVEL SYSTEMS INC' |
VendorID 0x135F, 'I-DATA INTERNATIONAL A-S' |
VendorID 0x1360, 'MEINBERG FUNKUHREN' |
VendorID 0x1363, 'PHOENIX TECHNOLOGIES LTD' |
VendorID 0x1365, 'HYPERCOPE' |
VendorID 0x1367, 'HITACHI ZOSEN CORPORATION' |
VendorID 0x1368, 'SKYWARE CORPORATION' |
VendorID 0x1369, 'DIGIGRAM' |
VendorID 0x136B, 'KAWASAKI STEEL CORPORATION' |
VendorID 0x136C, 'ADTEK SYSTEM SCIENCE CO LTD' |
VendorID 0x1375, 'BOEING-SUNNYVALE' |
VendorID 0x1376, 'LAN Media Corporation' |
VendorID 0x1377, 'ELECTRONIC EQUIPMENT PRODUCTION & DISTRIBUTION' |
VendorID 0x137A, 'MARK OF THE UNICORN INC' |
VendorID 0x137B, 'PPT VISION' |
VendorID 0x137C, 'IWATSU ELECTRIC CO LTD' |
VendorID 0x137D, 'DYNACHIP CORPORATION' |
VendorID 0x1380, 'SANRITZ AUTOMATION CO LTC' |
VendorID 0x1381, 'BRAINS CO. LTD' |
VendorID 0x1383, 'CONTROLNET INC' |
VendorID 0x1384, 'STELLAR SEMICONDUCTOR INC' |
VendorID 0x1385, 'NETGEAR' |
VendorID 0x1387, 'SYSTRAN CORP' |
VendorID 0x1388, 'HITACHI INFORMATION TECHNOLOGY CO LTD' |
VendorID 0x1389, 'APPLICOM INTERNATIONAL' |
VendorID 0x138A, 'SITERA' |
VendorID 0x138B, 'TOKIMEC INC' |
VendorID 0x138E, 'BASLER GMBH' |
VendorID 0x138F, 'PATAPSCO DESIGNS INC' |
VendorID 0x1393, 'MOXA TECHNOLOGIES CO LTD' |
VendorID 0x1394, 'LEVEL ONE COMMUNICATIONS' |
VendorID 0x1395, 'AMBICOM INC' |
VendorID 0x1396, 'CIPHER SYSTEMS INC' |
VendorID 0x1397, 'COLOGNE CHIP DESIGNS GMBH' |
VendorID 0x1398, 'CLARION CO. LTD' |
VendorID 0x1399, 'RIOS SYSTEMS CO LTD' |
VendorID 0x139A, 'ALACRITECH INC' |
VendorID 0x139C, 'QUANTUM 3D INC' |
VendorID 0x139D, 'XSTREAMS PLC/ EPL LIMITED' |
VendorID 0x139E, 'ECHOSTAR DATA NETWORKS' |
VendorID 0x139F, 'AETHRA S.R.L.' |
VendorID 0x13A0, 'CRYSTAL GROUP INC' |
VendorID 0x13A1, 'KAWASAKI HEAVY INDUSTRIES LTD' |
VendorID 0x13A2, 'OSITECH COMMUNICATIONS INC' |
VendorID 0x13A4, 'RASCOM INC' |
VendorID 0x13A7, 'TELES AG' |
VendorID 0x13A8, 'EXAR CORP.' |
VendorID 0x13A9, 'SIEMENS MEDICAL SYSTEMS' |
VendorID 0x13AA, 'NORTEL NETWORKS-BWA DIVISION' |
VendorID 0x13AF, 'T.SQWARE' |
VendorID 0x13B1, 'TAMURA CORPORATION' |
VendorID 0x13B4, 'WELLBEAN CO INC' |
VendorID 0x13B5, 'ARM Ltd' |
VendorID 0x13B6, 'DLoG GMBH' |
VendorID 0x13B8, 'NOKIA TELECOMMUNICATIONS OY' |
VendorID 0x13BD, 'SHARP CORPORATION' |
VendorID 0x13BF, 'SHAREWAVE INC' |
VendorID 0x13C0, 'Microgate Corp.' |
VendorID 0x13C1, '3ware Inc.' |
VendorID 0x13C2, 'TECHNOTREND SYSTEMTECHNIK GMBH' |
VendorID 0x13C3, 'JANZ COMPUTER AG' |
VendorID 0x13C6, 'CONDOR ENGINEERING INC' |
VendorID 0x13C7, 'BLUE CHIP TECHNOLOGY LTD' |
VendorID 0x13CA, 'IOMEGA CORPORATION' |
VendorID 0x13CC, 'METHEUS CORPORATION' |
VendorID 0x13CF, 'STUDIO AUDIO & VIDEO LTD' |
VendorID 0x13D0, 'B2C2' |
VendorID 0x13D1, 'ABOCOM SYSTEMS' |
VendorID 0x13D2, 'SHARK MULTIMEDIA INC' |
VendorID 0x13D3, 'IMC NETWORKS' |
VendorID 0x13D4, 'GRAPHICS MICROSYSTEMS INC' |
VendorID 0x13D6, 'K.I. TECHNOLOGY CO LTD' |
VendorID 0x13D7, 'TOSHIBA ENGINEERING CORPORATION' |
VendorID 0x13D8, 'PHOBOS CORPORATION' |
VendorID 0x13D9, 'APEX INC' |
VendorID 0x13DC, 'NETBOOST CORPORATION' |
VendorID 0x13DE, 'ABB ROBOTICS PRODUCTS' |
VendorID 0x13DF, 'E-TECH INC' |
VendorID 0x13E0, 'GVC CORPORATION' |
VendorID 0x13E3, 'NEST INC' |
VendorID 0x13E4, 'CALCULEX INC' |
VendorID 0x13E5, 'TELESOFT DESIGN LTD' |
VendorID 0x13E9, 'INTRASERVER TECHNOLOGY INC' |
VendorID 0x13EA, 'DALLAS SEMICONDUCTOR' |
VendorID 0x13F0, 'SUNDANCE TECHNOLOGY INC' |
VendorID 0x13F1, 'OCE-TECHNOLOGIES B.V.' |
VendorID 0x13F2, 'FORD MICROELECTRONICS INC' |
VendorID 0x13F4, 'TROIKA NETWORKS INC' |
VendorID 0x13F6, 'C-MEDIA ELECTRONICS INC' |
VendorID 0x13F9, 'NTT ADVANCED TECHNOLOGY CORP.' |
VendorID 0x13FB, 'AYDIN CORP' |
VendorID 0x13FD, 'MICRO SCIENCE INC' |
VendorID 0x1400, 'ARTX INC' |
VendorID 0x1402, 'Meilhaus Electronic GmbH Germany' |
VendorID 0x1404, 'FUNDAMENTAL SOFTWARE INC' |
VendorID 0x1406, 'OCE PRINTING SYSTEMS GmbH' |
VendorID 0x1407, 'LAVA COMPUTER MFG INC' |
VendorID 0x1408, 'ALOKA CO. LTD' |
VendorID 0x140A, 'DSP RESEARCH INC' |
VendorID 0x140B, 'RAMIX INC' |
VendorID 0x140D, 'MATSUSHITA ELECTRIC WORKS LTD' |
VendorID 0x1412, 'ICEnsemble' |
VendorID 0x1413, 'ADDONICS' |
VendorID 0x1415, 'OXFORD SEMICONDUCTOR LTD' |
VendorID 0x1418, 'KYUSHU ELECTRONICS SYSTEMS INC' |
VendorID 0x1419, 'EXCEL SWITCHING CORP' |
VendorID 0x141B, 'ZOOM TELEPHONICS INC' |
VendorID 0x141E, 'FANUC LTD' |
VendorID 0x1420, 'PSION DACOM PLC' |
VendorID 0x1428, 'EDEC CO LTD' |
VendorID 0x1429, 'UNEX TECHNOLOGY CORP' |
VendorID 0x142A, 'KINGMAX TECHNOLOGY INC' |
VendorID 0x142B, 'RADIOLAN' |
VendorID 0x142C, 'MINTON OPTIC INDUSTRY CO LTD' |
VendorID 0x142D, 'PIXSTREAM INC' |
VendorID 0x1430, 'ITT AEROSPACE/COMMUNICATIONS DIVISION' |
VendorID 0x1433, 'ELTEC ELEKTRONIK GMBH' |
VendorID 0x1436, 'CIS TECHNOLOGY INC' |
VendorID 0x1437, 'NISSIN INC CO' |
VendorID 0x1438, 'ATMEL-DREAM' |
VendorID 0x143F, 'LIGHTWELL CO LTD-ZAX DIVISION' |
VendorID 0x1441, 'AGIE SA' |
VendorID 0x1445, 'LOGICAL CO LTD' |
VendorID 0x1446, 'GRAPHIN CO. LTD' |
VendorID 0x1447, 'AIM GMBH' |
VendorID 0x144A, 'ADLINK Technology Inc' |
VendorID 0x144B, 'LORONIX INFORMATION SYSTEMS INC' |
VendorID 0x144D, 'SAMSUNG ELECTRONICS CO LTD' |
VendorID 0x1450, 'OCTAVE COMMUNICATIONS IND.' |
VendorID 0x1451, 'SP3D CHIP DESIGN GMBH' |
VendorID 0x1453, 'MYCOM INC' |
VendorID 0x1455, 'LOGIC PLUS PLUS INC' |
VendorID 0x1458, 'GIGA-BYTE TECHNOLOGY' |
VendorID 0x145C, 'CRYPTEK' |
VendorID 0x145F, 'BALDOR ELECTRIC COMPANY' |
VendorID 0x1460, 'DYNARC INC' |
VendorID 0x1461, 'AVERMEDIA Tech.' |
VendorID 0x1462, 'MICRO-STAR INTERNATIONAL CO LTD' |
VendorID 0x1463, 'FAST CORPORATION' |
VendorID 0x1464, 'INTERACTIVE CIRCUITS & SYSTEMS LTD' |
VendorID 0x1465, 'GN NETTEST TELECOM DIV.' |
VendorID 0x1468, 'AMBIT MICROSYSTEMS CORP.' |
VendorID 0x1469, 'CLEVELAND MOTION CONTROLS' |
VendorID 0x146C, 'RUBY TECH CORP.' |
VendorID 0x146D, 'TACHYON' |
VendorID 0x146E, 'WILLIAMS ELECTRONICS GAMES.' |
VendorID 0x1471, 'INTEGRATED TELECOM EXPRESS INC' |
VendorID 0x1473, 'ZAPEX TECHNOLOGIES INC' |
VendorID 0x1474, 'DOUG CARSON & ASSOCIATES' |
VendorID 0x1477, 'NET INSIGHT' |
VendorID 0x1478, 'DIATREND CORPORATION' |
VendorID 0x147B, 'ABIT Computer' |
VendorID 0x147F, 'NIHON UNISYS' |
VendorID 0x1482, 'ISYTEC-Integrierte Systemtechnik Gmbh' |
VendorID 0x1483, 'LABWAY COPORATION' |
VendorID 0x1485, 'ERMA-ELECTRONIC GMBH' |
VendorID 0x1489, 'KYE SYSTEMS CORPORATION' |
VendorID 0x148A, 'OPTO 22' |
VendorID 0x148B, 'INNOMEDIALOGIC INC.' |
VendorID 0x148E, 'OSI PLUS CORPORATION' |
VendorID 0x148F, 'PLANT EQUIPMENT.' |
VendorID 0x1490, 'TC LABS PTY LTD.' |
VendorID 0x1493, 'MAKER COMMUNICATIONS' |
VendorID 0x1495, 'TOKAI COMMUNICATIONS INDUSTRY CO. LTD' |
VendorID 0x1496, 'JOYTECH COMPUTER CO. LTD.' |
VendorID 0x1497, 'SMA REGELSYSTEME GMBH' |
VendorID 0x1499, 'EMTEC CO. LTD' |
VendorID 0x149A, 'ANDOR TECHNOLOGY LTD' |
VendorID 0x149B, 'SEIKO INSTRUMENTS INC' |
VendorID 0x149C, 'OVISLINK CORP.' |
VendorID 0x149D, 'NEWTEK INC' |
VendorID 0x149E, 'MAPLETREE NETWORKS INC.' |
VendorID 0x149F, 'LECTRON CO LTD' |
VendorID 0x14A0, 'SOFTING GMBH' |
VendorID 0x14A1, 'SYSTEMBASE CO LTD' |
VendorID 0x14A2, 'MILLENNIUM ENGINEERING INC' |
VendorID 0x14A3, 'MAVERICK NETWORKS' |
VendorID 0x14A4, 'GVC/BCM ADVANCED RESEARCH' |
VendorID 0x14A5, 'XIONICS DOCUMENT TECHNOLOGIES INC.' |
VendorID 0x14A6, 'INOVA COMPUTERS GMBH & CO KG' |
VendorID 0x14A8, 'FEATRON TECHNOLOGIES CORPORATION' |
VendorID 0x14A9, 'HIVERTEC INC.' |
VendorID 0x14AB, 'MENTOR GRAPHICS CORP.' |
VendorID 0x14AC, 'NOVAWEB TECHNOLOGIES INC' |
VendorID 0x14AD, 'TIME SPACE RADIO AB' |
VendorID 0x14AE, 'CTI PET Systems' |
VendorID 0x14AF, 'GUILLEMOT CORPORATION' |
VendorID 0x14B0, 'BST COMMUNICATION TECHNOLOGY LTD' |
VendorID 0x14B1, 'NEXTCOM K.K.' |
VendorID 0x14B2, 'ENNOVATE NETWORKS INC' |
VendorID 0x14B3, 'XPEED INC.' |
VendorID 0x14B4, 'PHILIPS BUSINESS ELECTRONICS B.V.' |
VendorID 0x14B5, 'CREAMWARE GMBH' |
VendorID 0x14B6, 'QUANTUM DATA CORP.' |
VendorID 0x14B7, 'PROXIM INC' |
VendorID 0x14B8, 'TECHSOFT TECHNOLOGY CO LTD' |
VendorID 0x14B9, 'AIRONET WIRELESS COMMUNICATIONS' |
VendorID 0x14BA, 'INTERNIX INC.' |
VendorID 0x14BB, 'SEMTECH CORPORATION' |
VendorID 0x14BC, 'GLOBESPAN SEMICONDUCTOR INC.' |
VendorID 0x14BD, 'CARDIO CONTROL N.V.' |
VendorID 0x14BE, 'L3 COMMUNICATIONS' |
VendorID 0x14BF, 'SPIDER COMMUNICATIONS INC.' |
VendorID 0x14C0, 'COMPAL ELECTRONICS INC' |
VendorID 0x14C1, 'MYRICOM INC.' |
VendorID 0x14C2, 'DTK COMPUTER' |
VendorID 0x14C3, 'MEDIATEK CORP.' |
VendorID 0x14C4, 'IWASAKI INFORMATION SYSTEMS CO LTD' |
VendorID 0x14C5, 'ABB AUTOMATION PRODUCTS' |
VendorID 0x14C6, 'DATA RACE INC' |
VendorID 0x14C7, 'MODULAR TECHNOLOY HOLDINGS LTD' |
VendorID 0x14C8, 'TURBOCOMM TECH. INC.' |
VendorID 0x14C9, 'ODIN TELESYSTEMS INC' |
VendorID 0x14CA, 'PE LOGIC CORP.' |
VendorID 0x14CB, 'Billionton Systems Inc./Cadmus Micro Inc.' |
VendorID 0x14CC, 'NAKAYO TELECOMMUNICATIONS INC' |
VendorID 0x14CD, 'UNIVERSAL SCIENTIFIC IND' |
VendorID 0x14CE, 'WHISTLE COMMUNICATIONS' |
VendorID 0x14CF, 'TEK MICROSYSTEMS INC.' |
VendorID 0x14D0, 'ERICSSON AXE R & D' |
VendorID 0x14D1, 'COMPUTER HI-TECH CO LTD' |
VendorID 0x14D2, 'TITAN ELECTRONICS INC' |
VendorID 0x14D3, 'CIRTECH (UK) LTD' |
VendorID 0x14D4, 'PANACOM TECHNOLOGY CORP' |
VendorID 0x14D5, 'NITSUKO CORPORATION' |
VendorID 0x14D6, 'ACCUSYS' |
VendorID 0x14D7, 'HIRAKAWA HEWTECH CORP' |
VendorID 0x14D8, 'HOPF ELEKTRONIK GMBH' |
VendorID 0x14D9, 'ALPHA PROCESSOR INC' |
VendorID 0x14DA, 'NATIONAL AEROSPACE LABORATORIES' |
VendorID 0x14DB, 'AVLAB TECHNOLOGY INC' |
VendorID 0x14DC, 'AMPLICON LIVELINE LTD' |
VendorID 0x14DD, 'IMODL INC.' |
VendorID 0x14DE, 'APPLIED INTEGRATION CORPORATION' |
VendorID 0x14DF, 'BASIS COMMUNICATIONS CORP' |
VendorID 0x14E1, 'INVERTEX' |
VendorID 0x14E2, 'INFOLIBRIA' |
VendorID 0x14E3, 'AMTELCO' |
VendorID 0x14E4, 'BROADCOM CORPORATION' |
VendorID 0x14E5, 'PIXELFUSION LTD' |
VendorID 0x14E6, 'SHINING TECHNOLOGY INC' |
VendorID 0x14E7, '3CX' |
VendorID 0x14E8, 'RAYCER INC' |
VendorID 0x14E9, 'GARNETS SYSTEM CO LTD' |
VendorID 0x14EA, 'PLANEX COMMUNICATIONS INC' |
VendorID 0x14EB, 'SEIKO EPSON CORPORATION' |
VendorID 0x14EC, 'ACQIRIS' |
VendorID 0x14ED, 'DATAKINETICS LTD' |
VendorID 0x14EE, 'MASPRO KENKOH CORP' |
VendorID 0x14EF, 'CARRY COMPUTER ENG. CO LTD' |
VendorID 0x14F0, 'CANON RESEACH CENTRE FRANCE' |
VendorID 0x14F1, 'Conexant Systems, Inc' |
VendorID 0x14F2, 'Mobility Electronics, Inc.' |
VendorID 0x14F3, 'BROADLOGIC' |
VendorID 0x14F4, 'TOKYO ELECTRONIC INDUSTRY CO LTD' |
VendorID 0x14F5, 'SOPAC LTD' |
VendorID 0x14F6, 'COYOTE TECHNOLOGIES LLC' |
VendorID 0x14F7, 'WOLF TECHNOLOGY INC' |
VendorID 0x14F8, 'AUDIOCODES INC' |
VendorID 0x14F9, 'AG COMMUNICATIONS' |
VendorID 0x14FA, 'WAVETEK WANDEL & GOLTERMANN' |
VendorID 0x14FB, 'TRANSAS MARINE (UK) LTD' |
VendorID 0x14FC, 'QUADRICS SUPERCOMPUTERS WORLD' |
VendorID 0x14FD, 'JAPAN COMPUTER INDUSTRY INC.' |
VendorID 0x14FE, 'ARCHTEK TELECOM CORP.' |
VendorID 0x14FF, 'TWINHEAD INTERNATIONAL CORP' |
VendorID 0x1500, 'LANTECH COMPUTER COMPANY' |
VendorID 0x1501, 'BANKSOFT CANADA LTD' |
VendorID 0x1502, 'MITSUBISHI ELECTRIC LOGISTICS SUPPORT CO' |
VendorID 0x1503, 'KAWASAKI LSI USA INC' |
VendorID 0x1504, 'KAISER ELECTRONICS' |
VendorID 0x1505, 'ITA INGENIEURBURO FUR TESTAUFGABEN GMBH' |
VendorID 0x1506, 'CHAMELEON SYSTEMS INC' |
VendorID 0x1507, 'HTEC LTD' |
VendorID 0x1508, 'HONDA CONNECTORS/MHOTRONICS INC' |
VendorID 0x1509, 'FIRST INTERNATIONAL COMPUTER INC' |
VendorID 0x150A, 'FORVUS RESEARCH INC' |
VendorID 0x150B, 'YAMASHITA SYSTEMS CORP' |
VendorID 0x150C, 'KYOPAL CO LTD' |
VendorID 0x150D, 'WARPSPPED INC' |
VendorID 0x150E, 'C-PORT CORPORATION' |
VendorID 0x150F, 'INTEC GMBH' |
VendorID 0x1510, 'BEHAVIOR TECH COMPUTER CORP' |
VendorID 0x1511, 'CENTILLIUM TECHNOLOGY CORP' |
VendorID 0x1512, 'ROSUN TECHNOLOGIES INC' |
VendorID 0x1513, 'RAYCHEM' |
VendorID 0x1514, 'TFL LAN INC' |
VendorID 0x1515, 'ICS ADVENT' |
VendorID 0x1516, 'MYSON TECHNOLOGY INC' |
VendorID 0x1517, 'ECHOTEK CORPORATION' |
VendorID 0x1518, 'PEP MODULAR COMPUTERS GMBH' |
VendorID 0x1519, 'TELEFON AKTIEBOLAGET LM Ericsson' |
VendorID 0x151A, 'GLOBETEK INC' |
VendorID 0x151B, 'COMBOX LTD' |
VendorID 0x151C, 'DIGITAL AUDIO LABS INC' |
VendorID 0x151D, 'FUJITSU COMPUTER PRODUCTS OF AMERICA' |
VendorID 0x151E, 'MATRIX CORP.' |
VendorID 0x151F, 'TOPIC SEMICONDUCTOR CORP' |
VendorID 0x1520, 'CHAPLET SYSTEM INC' |
VendorID 0x1521, 'BELL CORPORATION' |
VendorID 0x1522, 'MAINPINE LIMITED' |
VendorID 0x1523, 'MUSIC SEMICONDUCTORS' |
VendorID 0x1524, 'ENE TECHNOLOGY INC' |
VendorID 0x1525, 'IMPACT TECHNOLOGIES' |
VendorID 0x1526, 'ISS' |
VendorID 0x1527, 'SOLECTRON' |
VendorID 0x1528, 'ACKSYS' |
VendorID 0x1529, 'AMERICAN MICROSYSTEMS INC' |
VendorID 0x152A, 'QUICKTURN DESIGN SYSTEMS' |
VendorID 0x152B, 'FLYTECH TECHNOLOGY CO LTD' |
VendorID 0x152C, 'MACRAIGOR SYSTEMS LLC' |
VendorID 0x152D, 'QUANTA COMPUTER INC' |
VendorID 0x152E, 'MELEC INC' |
VendorID 0x152F, 'PHILIPS-CRYPTO' |
VendorID 0x1530, 'ACQIS TECHNOLOGY' |
VendorID 0x1531, 'CHRYON CORP.' |
VendorID 0x1532, 'ECHELON CORPORATION' |
VendorID 0x1533, 'BALTIMORE' |
VendorID 0x1534, 'ROAD CORPORATION' |
VendorID 0x1535, 'EVERGREEN TECHNOLOGIES INC' |
VendorID 0x1537, 'DATALEX COMMUNCATIONS' |
VendorID 0x1538, 'ARALION INC.' |
VendorID 0x1539, 'ATELIER INFORMATIQUES et ELECTRONIQUE ETUDES S.A.' |
VendorID 0x153A, 'ONO SOKKI' |
VendorID 0x153B, 'TERRATEC ELECTRONIC GMBH' |
VendorID 0x153C, 'ANTAL ELECTRONIC' |
VendorID 0x153D, 'FILANET CORPORATION' |
VendorID 0x153E, 'TECHWELL INC' |
VendorID 0x153F, 'MIPS DENMARK' |
VendorID 0x1540, 'PROVIDEO MULTIMEDIA CO LTD' |
VendorID 0x1541, 'TELOSITY INC.' |
VendorID 0x1542, 'VIVID TECHNOLOGY INC' |
VendorID 0x1543, 'SILICON LABORATORIES' |
VendorID 0x1544, 'DCM DATA SYSTEMS' |
VendorID 0x1545, 'VISIONTEK' |
VendorID 0x1546, 'IOI TECHNOLOGY CORP.' |
VendorID 0x1547, 'MITUTOYO CORPORATION' |
VendorID 0x1548, 'JET PROPULSION LABORATORY' |
VendorID 0x1549, 'INTERCONNECT SYSTEMS SOLUTIONS' |
VendorID 0x154A, 'MAX TECHNOLOGIES INC.' |
VendorID 0x154B, 'COMPUTEX CO LTD' |
VendorID 0x154C, 'VISUAL TECHNOLOGY INC.' |
VendorID 0x154D, 'PAN INTERNATIONAL INDUSTRIAL CORP' |
VendorID 0x154E, 'SERVOTEST LTD' |
VendorID 0x154F, 'STRATABEAM TECHNOLOGY' |
VendorID 0x1550, 'OPEN NETWORK CO LTD' |
VendorID 0x1551, 'SMART ELECTRONIC DEVELOPMENT GMBH' |
VendorID 0x1552, 'RACAL AIRTECH LTD' |
VendorID 0x1553, 'CHICONY ELECTRONICS CO LTD' |
VendorID 0x1554, 'PROLINK MICROSYSTEMS CORP.' |
VendorID 0x1555, 'GESYTEC GMBH' |
VendorID 0x1556, 'PLD APPLICATIONS' |
VendorID 0x1557, 'MEDIASTAR CO. LTD' |
VendorID 0x1558, 'CLEVO/KAPOK COMPUTER' |
VendorID 0x1559, 'SI LOGIC LTD' |
VendorID 0x155A, 'INNOMEDIA INC' |
VendorID 0x155B, 'PROTAC INTERNATIONAL CORP' |
VendorID 0x155C, 'CEMAX-ICON INC' |
VendorID 0x155D, 'MAC SYSTEM CO LTD' |
VendorID 0x155E, 'LP ELEKTRONIK GMBH/KUKA Controls GmbH' |
VendorID 0x155F, 'PERLE SYSTEMS LIMITED' |
VendorID 0x1560, 'TERAYON COMMUNICATIONS SYSTEMS' |
VendorID 0x1561, 'VIEWGRAPHICS INC' |
VendorID 0x1562, 'Symbol Technologies, Inc.' |
VendorID 0x1563, 'A-TREND' |
VendorID 0x1564, 'YAMAKATSU ELECTRONICS INDUSTRY CO LTD' |
VendorID 0x1565, 'BIOSTAR MICROTECH INT CORP' |
VendorID 0x1566, 'ARDENT TECHNOLOGIES INC' |
VendorID 0x1567, 'JUNGSOFT' |
VendorID 0x1568, 'DDK ELECTRONICS INC' |
VendorID 0x1569, 'PALIT MICROSYSTEMS INC' |
VendorID 0x156A, 'AVTEC SYSTEMS' |
VendorID 0x156B, '2WIRE' |
VendorID 0x156C, 'VIDAC ELECTRONICS GMBH' |
VendorID 0x156D, 'ALPHA-TOP CORP' |
VendorID 0x156E, 'ALFA INC' |
VendorID 0x156F, 'M-SYSTEMS FLASH DISK PIONEERS LTD' |
VendorID 0x1570, 'LECROY CORPORATION' |
VendorID 0x1571, 'CONTEMPORARY CONTROLS' |
VendorID 0x1572, 'OTIS ELEVATOR COMPANY' |
VendorID 0x1573, 'LATTICE-VANTIS' |
VendorID 0x1574, 'FAIRCHILD SEMICONDUCTOR' |
VendorID 0x1575, 'VOLTAIRE ADVANCED DATA SECURITY LTD' |
VendorID 0x1576, 'VIEWCAST COM' |
VendorID 0x1578, 'HITT' |
VendorID 0x1579, 'DUAL TECHNOLOGY CORPORATION' |
VendorID 0x157A, 'JAPAN ELECRONICS IND. INC' |
VendorID 0x157B, 'STAR MULTIMEDIA CORP.' |
VendorID 0x157C, 'EUROSOFT (UK) LTD' |
VendorID 0x157D, 'GEMFLEX NETWORKS' |
VendorID 0x157E, 'TRANSITION NETWORKS' |
VendorID 0x157F, 'PX INSTRUMENTS TECHNOLOGY LTD' |
VendorID 0x1580, 'PRIMEX AEROSPACE CO.' |
VendorID 0x1581, 'SEH COMPUTERTECHNIK GMBH' |
VendorID 0x1582, 'CYTEC CORPORATION' |
VendorID 0x1583, 'INET TECHNOLOGIES INC' |
VendorID 0x1584, 'UNIWILL COMPUTER CORP' |
VendorID 0x1585, 'LOGITRON' |
VendorID 0x1586, 'LANCAST INC' |
VendorID 0x1587, 'KONICA CORPORATION' |
VendorID 0x1588, 'SOLIDUM SYSTEMS CORP' |
VendorID 0x1589, 'ATLANTEK MICROSYSTEMS PTY LTD' |
VendorID 0x158A, 'DIGALOG SYSTEMS INC' |
VendorID 0x158B, 'ALLIED DATA TECHNOLOGIES' |
VendorID 0x158C, 'HITACHI SEMICONDUCTOR & DEVICES SALES CO LTD' |
VendorID 0x158D, 'POINT MULTIMEDIA SYSTEMS' |
VendorID 0x158E, 'LARA TECHNOLOGY INC' |
VendorID 0x158F, 'DITECT COOP' |
VendorID 0x1590, '3PARDATA' |
VendorID 0x1591, 'ARN' |
VendorID 0x1592, 'SYBA TECH LIMITED' |
VendorID 0x1593, 'BOPS INC' |
VendorID 0x1594, 'NETGAME LTD' |
VendorID 0x1595, 'DIVA SYSTEMS CORP.' |
VendorID 0x1596, 'FOLSOM RESEARCH INC' |
VendorID 0x1597, 'MEMEC DESIGN SERVICES' |
VendorID 0x1598, 'GRANITE MICROSYSTEMS' |
VendorID 0x1599, 'DELTA ELECTRONICS INC' |
VendorID 0x159A, 'GENERAL INSTRUMENT' |
VendorID 0x159B, 'FARADAY TECHNOLOGY CORP' |
VendorID 0x159C, 'STRATUS COMPUTER SYSTEMS' |
VendorID 0x159D, 'NINGBO HARRISON ELECTRONICS CO LTD' |
VendorID 0x159E, 'A-MAX TECHNOLOGY' |
VendorID 0x159F, 'GALEA NETWORK SECURITY' |
VendorID 0x15A0, 'COMPUMASTER SRL' |
VendorID 0x15A1, 'GEOCAST NETWORK SYSTEMS INC' |
VendorID 0x15A2, 'CATALYST ENTERPRISES INC' |
VendorID 0x15A3, 'ITALTEL' |
VendorID 0x15A4, 'X-NET OY' |
VendorID 0x15A5, 'TOYOTA MACS INC' |
VendorID 0x15A6, 'SUNLIGHT ULTRASOUND TECHNOLOGIES LTD' |
VendorID 0x15A7, 'SSE TELECOM INC' |
VendorID 0x15A8, 'SHANGHAI COMMUNICATIONS TECHNOLOGIES CENTER' |
VendorID 0x15AA, 'MORETON BAY' |
VendorID 0x15AB, 'BLUESTEEL NETWORKS INC' |
VendorID 0x15AC, 'NORTH ATLANTIC INSTRUMENTS' |
VendorID 0x15AD, 'VMware Inc.' |
VendorID 0x15AE, 'AMERSHAM PHARMACIA BIOTECH' |
VendorID 0x15B0, 'ZOLTRIX INTERNATIONAL LIMITED' |
VendorID 0x15B1, 'SOURCE TECHNOLOGY INC' |
VendorID 0x15B2, 'MOSAID TECHNOLOGIES INC.' |
VendorID 0x15B3, 'MELLANOX TECHNOLOGY' |
VendorID 0x15B4, 'CCI/TRIAD' |
VendorID 0x15B5, 'CIMETRICS INC' |
VendorID 0x15B6, 'TEXAS MEMORY SYSTEMS INC' |
VendorID 0x15B7, 'SANDISK CORP.' |
VendorID 0x15B8, 'ADDI-DATA GMBH' |
VendorID 0x15B9, 'MAESTRO DIGITAL COMMUNICATIONS' |
VendorID 0x15BA, 'IMPACCT TECHNOLOGY CORP' |
VendorID 0x15BB, 'PORTWELL INC' |
VendorID 0x15BC, 'AGILENT TECHNOLOGIES' |
VendorID 0x15BD, 'DFI INC.' |
VendorID 0x15BE, 'SOLA ELECTRONICS' |
VendorID 0x15BF, 'HIGH TECH COMPUTER CORP (HTC)' |
VendorID 0x15C0, 'BVM LIMITED' |
VendorID 0x15C1, 'QUANTEL' |
VendorID 0x15C2, 'NEWER TECHNOLOGY INC' |
VendorID 0x15C3, 'TAIWAN MYCOMP CO LTD' |
VendorID 0x15C4, 'EVSX' |
VendorID 0x15C5, 'PROCOMP INFORMATICS LTD' |
VendorID 0x15C6, 'TECHNICAL UNIVERSITY OF BUDAPEST' |
VendorID 0x15C7, 'TATEYAMA SYSTEM LABORATORY CO LTD' |
VendorID 0x15C8, 'PENTA MEDIA CO. LTD' |
VendorID 0x15C9, 'SEROME TECHNOLOGY INC' |
VendorID 0x15CA, 'BITBOYS OY' |
VendorID 0x15CB, 'AG ELECTRONICS LTD' |
VendorID 0x15CC, 'HOTRAIL INC.' |
VendorID 0x15CD, 'DREAMTECH CO LTD' |
VendorID 0x15CE, 'GENRAD INC.' |
VendorID 0x15CF, 'HILSCHER GMBH' |
VendorID 0x15D1, 'INFINEON TECHNOLOGIES AG' |
VendorID 0x15D2, 'FIC (FIRST INTERNATIONAL COMPUTER INC)' |
VendorID 0x15D3, 'NDS TECHNOLOGIES ISRAEL LTD' |
VendorID 0x15D4, 'IWILL CORPORATION' |
VendorID 0x15D5, 'TATUNG CO.' |
VendorID 0x15D6, 'ENTRIDIA CORPORATION' |
VendorID 0x15D7, 'Rockwell-Collins Inc' |
VendorID 0x15D8, 'CYBERNETICS TECHNOLOGY CO LTD' |
VendorID 0x15D9, 'SUPER MICRO COMPUTER INC' |
VendorID 0x15DA, 'CYBERFIRM INC.' |
VendorID 0x15DB, 'APPLIED COMPUTING SYSTEMS INC.' |
VendorID 0x15DC, 'LITRONIC INC' |
VendorID 0x15DD, 'SIGMATEL INC.' |
VendorID 0x15DE, 'MALLEABLE TECHNOLOGIES INC' |
VendorID 0x15DF, 'INFINILINK CORP.' |
VendorID 0x15E0, 'CACHEFLOW INC' |
VendorID 0x15E1, 'VOICE TECHNOLOGIES GROUP INC' |
VendorID 0x15E2, 'QUICKNET TECHNOLOGIES INC' |
VendorID 0x15E3, 'NETWORTH TECHNOLOGIES INC' |
VendorID 0x15E4, 'VSN SYSTEMEN BV' |
VendorID 0x15E5, 'VALLEY TECHNOLOGIES INC' |
VendorID 0x15E6, 'AGERE INC.' |
VendorID 0x15E7, 'GET ENGINEERING CORP.' |
VendorID 0x15E8, 'NATIONAL DATACOMM CORP.' |
VendorID 0x15E9, 'PACIFIC DIGITAL CORP.' |
VendorID 0x15EA, 'TOKYO DENSHI SEKEI K.K.' |
VendorID 0x15EB, 'DRSEARCH GMBH' |
VendorID 0x15EC, 'BECKHOFF GMBH' |
VendorID 0x15ED, 'MACROLINK INC' |
VendorID 0x15EE, 'IN WIN DEVELOPMENT INC.' |
VendorID 0x15EF, 'INTELLIGENT PARADIGM INC' |
VendorID 0x15F0, 'B-TREE SYSTEMS INC' |
VendorID 0x15F1, 'TIMES N SYSTEMS INC' |
VendorID 0x15F2, 'DIAGNOSTIC INSTRUMENTS INC' |
VendorID 0x15F3, 'DIGITMEDIA CORP.' |
VendorID 0x15F4, 'VALUESOFT' |
VendorID 0x15F5, 'POWER MICRO RESEARCH' |
VendorID 0x15F6, 'EXTREME PACKET DEVICE INC' |
VendorID 0x15F7, 'BANCTEC' |
VendorID 0x15F8, 'KOGA ELECTRONICS CO' |
VendorID 0x15F9, 'ZENITH ELECTRONICS CORPORATION' |
VendorID 0x15FA, 'J P AXZAM CORPORATION' |
VendorID 0x15FB, 'ZILOG INC.' |
VendorID 0x15FC, 'TECHSAN ELECTRONICS CO LTD' |
VendorID 0x15FD, 'N-CUBED.NET' |
VendorID 0x15FE, 'KINPO ELECTRONICS INC' |
VendorID 0x15FF, 'FASTPOINT TECHNOLOGIES INC.' |
VendorID 0x1600, 'NORTHROP GRUMMAN-CANADA LTD' |
VendorID 0x1601, 'TENTA TECHNOLOGY' |
VendorID 0x1602, 'PROSYS-TEC INC.' |
VendorID 0x1603, 'NOKIA WIRELESS BUSINESS COMMUNICATIONS' |
VendorID 0x1604, 'CENTRAL SYSTEM RESEARCH CO LTD' |
VendorID 0x1605, 'PAIRGAIN TECHNOLOGIES' |
VendorID 0x1606, 'EUROPOP AG' |
VendorID 0x1607, 'LAVA SEMICONDUCTOR MANUFACTURING INC.' |
VendorID 0x1608, 'AUTOMATED WAGERING INTERNATIONAL' |
VendorID 0x1609, 'SCIEMETRIC INSTRUMENTS INC' |
VendorID 0x166D, 'Broadcom -SiByte' |
VendorID 0x168C, 'Atheros Communications Inc.' |
VendorID 0x1695, 'EPOX Computer Co' |
VendorID 0x17F2, 'ALBATRON Corp.' |
VendorID 0x1813, 'AMBIENT TECHNOLOGIES INC' |
VendorID 0x1849, 'ASROCK Inc' |
VendorID 0x1B13, 'Jaton Corp' |
VendorID 0x2001, 'TEMPORAL RESEARCH LTD' |
VendorID 0x270F, 'CHAINTECH COMPUTER CO. LTD' |
VendorID 0x3388, 'HINT CORP' |
VendorID 0x3411, 'QUANTUM DESIGNS (H.K.) INC.' |
VendorID 0x4005, 'AVANCE LOGIC INC' |
VendorID 0x4033, 'DELTA NETWORKS INC' |
VendorID 0x416C, 'ALADDIN KNOWLEDGE SYSTEMS' |
VendorID 0x4444, 'CONEXANT (WAS ICOMPRESION INC.)' |
VendorID 0x4943, 'GROWTH NETWORKS' |
VendorID 0x4CA1, 'SEANIX TECHNOLOGY INC' |
VendorID 0x4D51, 'MEDIAQ INC.' |
VendorID 0x4D54, 'MICROTECHNICA CO LTD' |
VendorID 0x5136, 'S S TECHNOLOGIES' |
VendorID 0x5333, 'S3 Graphics Co., Ltd.' |
VendorID 0x544C, 'TERALOGIC INC' |
VendorID 0x5555, 'GENROCO INC' |
VendorID 0x6409, 'LOGITEC CORP.' |
VendorID 0x6666, 'DECISION COMPUTER INTERNATIONAL CO.' |
VendorID 0x8086, 'Intel Corp.' |
VendorID 0x8888, 'SILICON MAGIC CORP.' |
VendorID 0x8E0E, 'COMPUTONE CORPORATION' |
VendorID 0x9004, 'Adaptec Inc' |
VendorID 0x919A, 'GIGAPIXEL CORP' |
VendorID 0x9412, 'HOLTEK' |
VendorID 0x9699, 'OMNI MEDIA TECHNOLOGY INC.' |
VendorID 0x9710, 'NetMos' |
VendorID 0xA0A0, 'AOPEN INC.' |
VendorID 0xA259, 'HEWLETT PACKARD' |
VendorID 0xAC1E, 'DIGITAL RECEIVER TECHNOLOGY INC' |
VendorID 0xC0DE, 'MOTOROLA' |
VendorID 0xC0FE, 'MOTION ENGINEERING.' |
VendorID 0xCA50, 'VARIAN AUSTRIALIA PTY LTD' |
VendorID 0xCAFE, 'CHRYSALIS-ITS' |
VendorID 0xCCCC, 'CATAPULT COMMUNICATIONS' |
VendorID 0xD4D4, 'DY4 Systems Inc/Curtiss-Wright Controls Embed. Com' |
VendorID 0xE159, 'TigerJet' |
VendorID 0xE4BF, 'EKF ELEKTRONIK GMBH' |
VendorID 0xEA01, 'EAGLE TECHNOLOGY' |
VendorID 0xFA57, 'FAST SEARCH & TRANSFER ASA' |
VendorID 0xFEDA, 'EPIGRAM INC' |
VendorID 0, 'Unknown' ; <- terminator |
;-------------------------------------- |
Classes: |
; Class, Subclass, [Interface], Name |
ClassID 2, 0, , 'Ethernet' |
ClassID 2, 1, , 'Token Ring' |
ClassID 2, 2, , 'FDDI' |
ClassID 2, 3, , 'ATM' |
ClassID 2, 4, , 'ISDN' |
ClassID 2, 5, , 'WorldFip' |
ClassID 2, 6, , 'PICMG 2.14' |
ClassID 2, 0x80, , 'misc' |
ClassID 0x0d, 0x20, , 'Wlan (802.11a)' |
ClassID 0x0d, 0x21, , 'Wlan (802.11b)' |
ClassID 0xff, 0xff, , 'Unknown' ; <- terminator |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/netcfg/drivers.inc |
---|
0,0 → 1,198 |
driverlist: |
db 'RTL8139',0 |
dd 0x813910ec |
dd 0x813810ec |
dd 0x12111113 |
dd 0x13601500 |
dd 0x13604033 |
dd 0x13001186 |
dd 0x13401186 |
dd 0xab0613d1 |
dd 0xa1171259 |
dd 0xa11e1259 |
dd 0xab0614ea |
dd 0xab0714ea |
dd 0x123411db |
dd 0x91301432 |
dd 0x101202ac |
dd 0x0106018a |
dd 0x1211126c |
dd 0x81391743 |
dd 0x8139021b |
dd 0x0 ; end |
db 'RTL8029',0 |
dd 0x802910ec |
dd 0x0 |
db 'I8255X',0 |
dd 0x12098086 |
dd 0x10298086 |
dd 0x12298086 |
dd 0x10308086 |
dd 0x24498086 |
dd 0x0 |
db 'RTL8169',0 |
dd 0x816810ec |
dd 0x816910ec |
dd 0x011616ec |
dd 0x43001186 |
dd 0x813610ec |
dd 0x0 |
db '3C59X',0 |
dd 0x590010b7 |
dd 0x592010b7 |
dd 0x597010b7 |
dd 0x595010b7 |
dd 0x595110b7 |
dd 0x595210b7 |
dd 0x900010b7 |
dd 0x900110b7 |
dd 0x900410b7 |
dd 0x900510b7 |
dd 0x900610b7 |
dd 0x900A10b7 |
dd 0x905010b7 |
dd 0x905110b7 |
dd 0x905510b7 |
dd 0x905810b7 |
dd 0x905A10b7 |
dd 0x920010b7 |
dd 0x980010b7 |
dd 0x980510b7 |
dd 0x764610b7 |
dd 0x505510b7 |
dd 0x605510b7 |
dd 0x605610b7 |
dd 0x5b5710b7 |
dd 0x505710b7 |
dd 0x515710b7 |
dd 0x525710b7 |
dd 0x656010b7 |
dd 0x656210b7 |
dd 0x656410b7 |
dd 0x450010b7 |
dd 0x0 |
db 'SIS900',0 |
dd 0x09001039 |
dd 0x70161039 |
dd 0x0 |
db 'PCNET32',0 |
dd 0x20001022 |
dd 0x26251022 |
dd 0x20011022 |
dd 0x0 |
db 'FORCEDETH',0 |
dd 0x006610de |
dd 0x01c310de |
dd 0x00D610de |
dd 0x008610de |
dd 0x008c10de |
dd 0x00e610de |
dd 0x00df10de |
dd 0x005610de |
dd 0x005710de |
dd 0x003710de |
dd 0x003810de |
dd 0x026810de |
dd 0x026910de |
dd 0x037210de |
dd 0x037310de |
dd 0x03e510de |
dd 0x03e610de |
dd 0x03ee10de |
dd 0x03ef10de |
dd 0x045010de |
dd 0x045110de |
dd 0x045210de |
dd 0x045310de |
dd 0x054c10de |
dd 0x054d10de |
dd 0x054e10de |
dd 0x054f10de |
dd 0x07dc10de |
dd 0x07dd10de |
dd 0x07de10de |
dd 0x07df10de |
dd 0x076010de |
dd 0x076110de |
dd 0x076210de |
dd 0x076310de |
dd 0x0ab010de |
dd 0x0ab110de |
dd 0x0ab210de |
dd 0x0ab310de |
dd 0x0d7d10de |
dd 0x0 |
db 'MTD80X',0 |
dd 0x08031516 |
dd 0x08001516 |
dd 0x08911516 |
dd 0x0 |
db 'dec21x4x',0 |
dd 0x00091011 |
dd 0x00191011 |
dd 0x09851317 |
dd 0x0 |
db 'R6040',0 |
dd 0x604017F3 |
dd 0x0 |
db 'i8254x',0 |
dd 0x10008086 ; 82542 (Fiber) |
dd 0x10018086 ; 82543GC (Fiber) |
dd 0x10048086 ; 82543GC (Copper) |
dd 0x10088086 ; 82544EI (Copper) |
dd 0x10098086 ; 82544EI (Fiber) |
dd 0x100A8086 ; 82540EM |
dd 0x100C8086 ; 82544GC (Copper) |
dd 0x100D8086 ; 82544GC (LOM) |
dd 0x100E8086 ; 82540EM |
dd 0x100F8086 ; 82545EM (Copper) |
dd 0x10108086 ; 82546EB (Copper) |
dd 0x10118086 ; 82545EM (Fiber) |
dd 0x10128086 ; 82546EB (Fiber) |
dd 0x10138086 ; 82541EI |
dd 0x10148086 ; 82541ER |
dd 0x10158086 ; 82540EM (LOM) |
dd 0x10168086 ; 82540EP (Mobile) |
dd 0x10178086 ; 82540EP |
dd 0x10188086 ; 82541EI |
dd 0x10198086 ; 82547EI |
dd 0x101a8086 ; 82547EI (Mobile) |
dd 0x101d8086 ; 82546EB |
dd 0x101e8086 ; 82540EP (Mobile) |
dd 0x10268086 ; 82545GM |
dd 0x10278086 ; 82545GM |
dd 0x10288086 ; 82545GM |
dd 0x105b8086 ; 82546GB (Copper) |
dd 0x10758086 ; 82547GI |
dd 0x10768086 ; 82541GI |
dd 0x10778086 ; 82541GI |
dd 0x10788086 ; 82541ER |
dd 0x10798086 ; 82546GB |
dd 0x107a8086 ; 82546GB |
dd 0x107b8086 ; 82546GB |
dd 0x107c8086 ; 82541PI |
dd 0x10b58086 ; 82546GB (Copper) |
dd 0x11078086 ; 82544EI |
dd 0x11128086 ; 82544GC |
dd 0x0 |
db 'RHINE', 0 ; VIA Rhine |
dd 0x30431106 |
dd 0x61001106 |
dd 0x30651106 |
dd 0x31061106 |
dd 0x30531106 |
dd 0x0 |
dd 0x0 ; driverlist end |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/netcfg/netcfg.asm |
---|
0,0 → 1,548 |
; |
; Netcfg v1.02 |
; |
; Application to load network drivers in KolibriOS |
; |
; By hidnplayr |
; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 0x01 ; header version |
dd START ; start of code |
dd IM_END ; size of image |
dd (I_END+0x100) ; memory for app |
dd (I_END+0x100) ; esp |
dd param, 0x0 ; I_Param , I_Icon |
type_ethernet equ 1 |
include '../macros.inc' |
START: |
; first, check boot parameters |
cmp byte[param], 0 |
je .noparams |
mcall 40, 0 |
push .exit |
cmp byte[param], 'A' ; A for All |
je Get_PCI_Info |
cmp byte[param], 'F' ; F for First |
je Get_PCI_Info |
ret |
.exit: |
mcall -1 |
.noparams: |
call draw_window |
still: |
mcall 10 ; wait here for event |
dec eax ; redraw request ? |
jz red |
dec eax ; key in buffer ? |
jz key |
dec eax ; button in buffer ? |
jz button |
jmp still |
red: ; redraw |
mcall 9, Proc_Info, -1 ; window redraw requested so get new window coordinates and size |
mov eax, [Proc_Info.box.left]; store the window coordinates into the Form Structure |
mov [Form + 2], ax ; x start position |
mov eax, [Proc_Info.box.top]; |
mov [Form + 6], ax ; ystart position |
mov eax, [Proc_Info.box.width] ; |
mov [Form], ax ; window width |
mov eax, [Proc_Info.box.height] ; |
mov [Form + 4] ,ax ; window height |
call draw_window ; go redraw window now |
jmp still |
key: ; key |
mcall 2 ; just read it and ignore |
jmp still |
button: ; button |
mcall 17 ; get id |
cmp ah, 1 ; button id = 1 ? |
jne @f |
exit: mcall -1 ; close this program |
@@: |
cmp eax,0x0000ff00 |
jg load_drv |
cmp ah, 4 |
je hook |
cmp ah, 5 |
je reset |
cmp ah, 6 |
je unload |
jmp still |
load_drv: |
shr eax, 16 |
mov word [selected], ax |
mov bl , 6 ; get a dword |
mov bh , ah ; bus |
mov ch , al ; dev |
mov cl , 0 ; offset to device/vendor id |
mcall 62 ; get ID's |
mov word [PCI_Vendor], ax |
shr eax, 16 |
mov word [PCI_Device], ax |
call get_drv_ptr |
mov ecx, eax |
mcall 68, 16 |
mov [IOCTL.handle], eax |
call draw_window |
cmp [IOCTL.handle], 0 |
jne still |
mcall 4, 20 shl 16 + 30, 1 shl 31 + 0x00ff0000 , load_error |
jmp still |
hook: |
mov ax , [selected] |
test ax , ax |
jz still |
mov [hardwareinfo.pci_dev], al |
mov [hardwareinfo.pci_bus], ah |
mov [IOCTL.io_code], 1 ; SRV_HOOK |
mov [IOCTL.inp_size], 3 |
mov [IOCTL.input], hardwareinfo |
mov [IOCTL.out_size], 0 |
mov [IOCTL.output], 0 |
mcall 68, 17, IOCTL |
mov byte[drivernumber], al |
jmp still |
reset: |
movzx ebx, byte[drivernumber] |
mcall 74,,2 |
jmp still |
unload: |
movzx ebx, byte[drivernumber] |
mcall 74,,3 |
jmp still |
draw_window: |
mcall 12, 1 ; start of draw |
mcall 0, dword [Form], dword [Form + 4], 0x13ffffff, 0x805080d0, title |
call Get_PCI_Info ; get pci version and last bus, scan for and draw each pci device |
cmp edx, 20 shl 16 + 110 |
je .nonefound |
mcall 4, 20 shl 16 + 100, 1 shl 31 + 0x00000000 , caption |
cmp [selected], 0 |
jz .done |
cmp [IOCTL.handle] ,0 |
jz .done |
mcall 8, 18 shl 16 + 100, 35 shl 16 + 18, 4, 0x00007f00 |
mcall ,, 55 shl 16 + 18, 5, 0x0000007f |
mcall ,, 75 shl 16 + 18, 6, 0x007f0000 |
mcall 4, 33 shl 16 + 42, 1 shl 31 + 0x00ffffff , btn_start |
mcall , 33 shl 16 + 62, , btn_reset |
mcall , 36 shl 16 + 82, , btn_stop |
jmp .done |
.nonefound: |
mcall 4, 20 shl 16 + 30, 1 shl 31 + 0x00ff0000 , nonefound |
.done: |
mcall 12, 2 ; end of draw |
ret |
;------------------------------------------------------------------ |
;* Gets the PCI Version and Last Bus |
Get_PCI_Info: |
mcall 62, 0 |
mov word [PCI_Version], ax |
mcall 62, 1 |
mov byte [PCI_LastBus], al |
;---------------------------------------------------------- |
;* Get all devices on PCI Bus |
mov edx, 20 shl 16 + 110 ; set start write position |
cmp al , 0xff ; 0xFF means no pci bus found |
jne Pci_Exists ; |
ret ; if no bus then leave |
Pci_Exists: |
mov byte [V_Bus], 0 ; reset varibles |
mov byte [V_Dev], 0 ; |
Start_Enum: |
mov bl , 6 ; get a dword |
mov bh , byte [V_Bus] ; bus of pci device |
mov ch , byte [V_Dev] ; device number/function |
mov cl , 0 ; offset to device/vendor id |
mcall 62 ; get ID's |
cmp ax, 0 ; Vendor ID should not be 0 or 0xFFFF |
je nextDev ; check next device if nothing exists here |
cmp ax, 0xffff ; |
je nextDev ; |
mov word [PCI_Vendor], ax ; There is a device here, save the ID's |
shr eax, 16 ; |
mov word [PCI_Device], ax ; |
mov bl , 4 ; Read config byte |
mov bh , byte [V_Bus] ; Bus # |
mov ch , byte [V_Dev] ; Device # on bus |
mov cl , 0x08 ; Register to read (Get Revision) |
mcall 62 ; Read it |
mov byte [PCI_Rev], al ; Save it |
mov cl , 0x0b ; Register to read (Get class) |
mcall 62 ; Read it |
mov byte [PCI_Class], al ; Save it |
mov cl , 0x0a ; Register to read (Get Subclass) |
mcall 62 ; Read it |
mov byte [PCI_SubClass], al ; Save it |
mov cl , 0x09 ; Register to read (Get Interface) |
mcall 62 ; Read it |
mov [PCI_Interface], al ; Save it |
mov cl , 0x3c ; Register to read (Get IRQ) |
@@: mcall 62 ; Read it |
mov [PCI_IRQ], al ; Save it |
; cmp byte [PCI_Class], 0 ; device from before class codes |
; je @f |
cmp byte [PCI_Class], 2 ; network controller |
jne nextDev |
; @@: |
cmp byte[param], 0 |
jne load_and_start |
mov cl, 0x0e |
mcall 62 |
push eax |
call Print_New_Device ; print device info to screen |
pop eax |
test al, al |
js nextDev |
nextdev2: |
test byte [V_Dev], 7 |
jnz nextDev |
or byte [V_Dev], 7 |
nextDev: |
inc [V_Dev] ; lower 3 bits are the function number |
jnz Start_Enum ; jump until we reach zero |
mov byte [V_Dev], 0 ; reset device number |
inc byte [V_Bus] ; next bus |
mov al , byte [PCI_LastBus] ; get last bus |
cmp byte [V_Bus], al ; was it last bus |
jbe Start_Enum ; if not jump to keep searching |
ret |
load_and_start: |
call get_drv_ptr |
cmp eax, lbl_none |
je .next |
mov ecx, eax |
mcall 68, 16 |
test eax, eax |
jz .next |
mov [IOCTL.handle], eax |
mov al, [V_Dev] |
mov [hardwareinfo.pci_dev], al |
mov al, [V_Bus] |
mov [hardwareinfo.pci_bus], al |
mov [IOCTL.io_code], 1 ; SRV_HOOK |
mov [IOCTL.inp_size], 3 |
mov [IOCTL.input], hardwareinfo |
mov [IOCTL.out_size], 0 |
mov [IOCTL.output], 0 |
mcall 68, 17, IOCTL |
.next: |
cmp byte[param], 'A' |
je nextdev2 |
jmp exit |
;------------------------------------------------------------------ |
;* Print device info to screen |
Print_New_Device: |
push edx ; Magic ! (to print a button...) |
mov ebx, 18 shl 16 |
mov bx , [Form] |
sub bx , 36 |
mov cx , dx |
dec cx |
shl ecx, 16 |
add ecx, 9 |
movzx edx, byte [V_Bus] |
shl dx , 8 |
mov dl , byte [V_Dev] |
mov esi, 0x0000c0ff ; color: yellow if selected, blue otherwise |
cmp word [selected], dx |
jne @f |
mov esi, 0x00c0c000 |
@@: |
shl edx, 8 |
or dl , 0xff |
mcall 8 |
pop edx |
xor esi, esi ; Color of text |
movzx ecx, word [PCI_Vendor] ; number to be written |
mcall 47, 0x00040100 ; Write Vendor ID |
add edx, (4*6+18) shl 16 |
movzx ecx, word [PCI_Device] ; get Vendor ID |
mcall ; Draw Vendor ID to Window |
add edx, (4*6+18) shl 16 |
movzx ecx, byte [V_Bus] ; get bus number |
mcall ,0x00020100 ; draw bus number to screen |
add edx, (2*6+18) shl 16 |
movzx ecx, byte [V_Dev] ; get device number |
shr ecx, 3 ; device number is bits 3-7 |
mcall ; Draw device Number To Window |
add edx, (2*6+18) shl 16 |
movzx ecx, byte [PCI_Rev] ; get revision number |
mcall ; Draw Revision to screen |
add edx, (2*6+18) shl 16 |
movzx ecx, [PCI_IRQ] |
cmp cl , 0x0f ; IRQ must be between 0 and 15 |
ja @f |
mcall |
@@: |
; |
;Write Names |
movzx ebx, dx ; Set y position |
or ebx, 230 shl 16 ; set Xposition |
;------------------------------------------------------------------ |
; Prints the Vendor's Name based on Vendor ID |
;------------------------------------------------------------------ |
mov edx, VendorsTab |
mov cx , word[PCI_Vendor] |
.fn: mov ax , [edx] |
add edx, 6 |
test ax , ax |
jz .find |
cmp ax , cx |
jne .fn |
.find: mov edx, [edx - 4] |
mcall 4,, 0x80000000 ; lets print the vendor Name |
;------------------------------------------------------------------ |
; Get description based on Class/Subclass |
;------------------------------------------------------------------ |
mov eax, dword [PCI_Class] |
and eax, 0xffffff |
xor edx, edx |
xor esi, esi |
.fnc: inc esi |
mov ecx, [Classes + esi * 8 - 8] |
cmp cx , 0xffff |
je .endfc |
cmp cx , ax |
jne .fnc |
test ecx, 0xff000000 |
jz @f |
mov edx, [Classes + esi * 8 - 4] |
jmp .fnc |
@@: cmp eax, ecx |
jne .fnc |
xor edx, edx |
.endfc: test edx, edx |
jnz @f |
mov edx, [Classes + esi * 8 - 4] |
@@: |
add ebx, 288 shl 16 |
mcall 4,, 0x80000000,, 32 ; draw the text |
movzx edx, bx ; get y coordinate |
add edx, 0x0014000A ; add 10 to y coordinate and set x coordinate to 20 |
;------------------------------------------------------------------ |
; Print Driver Name |
;------------------------------------------------------------------ |
push edx |
add ebx, 120 shl 16 |
push ebx |
call get_drv_ptr |
mov edx, eax |
pop ebx |
mcall 4,,0x80000000 ; lets print the vendor Name |
pop edx |
ret |
get_drv_ptr: |
mov eax, driverlist ; eax will be the pointer to latest driver title |
mov ebx, driverlist ; ebx is the current pointer |
mov ecx, dword[PCI_Vendor] ; the device/vendor id of we want to find |
driverloop: |
inc ebx |
cmp byte[ebx],0 |
jne driverloop |
inc ebx ; the device/vendor id list for the driver eax is pointing to starts here. |
deviceloop: |
cmp dword[ebx],0 |
je nextdriver |
cmp dword[ebx],ecx |
je driverfound |
add ebx,4 |
jmp deviceloop |
nextdriver: |
add ebx,4 |
cmp dword[ebx],0 |
je nodriver |
mov eax,ebx |
jmp driverloop |
nodriver: |
mov eax, lbl_none ; lets print the vendor Name |
ret |
driverfound: |
ret |
include 'vendors.inc' |
include 'drivers.inc' |
;------------------------------------------------------------------ |
; DATA AREA |
DATA |
Form: dw 800 ; window width (no more, special for 800x600) |
dw 100 ; window x start |
dw 220 ; window height |
dw 100 ; window y start |
title db 'Network Driver Control Center', 0 |
caption db 'Vendor Device Bus Dev Rev IRQ Company Description DRIVER',0 |
nonefound db 'No compatible devices were found!',0 |
btn_start db 'Start device',0 |
btn_reset db 'Reset device',0 |
btn_stop db 'Stop device',0 |
lbl_none db 'none',0 |
load_error db 'Could not load driver!',0 |
hardwareinfo: |
.type db 1 ; pci |
.pci_bus db ? |
.pci_dev db ? |
IM_END: |
;------------------------------------------------------------------ |
; UNINITIALIZED DATA AREA |
IOCTL: |
.handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
drivernumber db ? |
MAC dp ? |
type db ? |
selected dw ? |
V_Bus db ? |
V_Dev db ? |
PCI_Version dw ? |
PCI_LastBus db ? |
PCI_Vendor dw ? |
PCI_Device dw ? |
PCI_Bus db ? |
PCI_Dev db ? |
PCI_Rev db ? |
; don`t change order!!! |
PCI_Class db ? |
PCI_SubClass db ? |
PCI_Interface db ? |
PCI_IRQ db ? |
Proc_Info process_information |
param rb 1024 |
I_END: |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/netstat/netstat.asm |
---|
0,0 → 1,614 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; netstat.asm - Network Status Tool for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 0x01 ; header version |
dd START ; start of code |
dd I_END ; size of image |
dd (I_END+0x100) ; memory for app |
dd (I_END+0x100) ; esp |
dd I_PARAM , 0x0 ; I_Param , I_Icon |
include '..\macros.inc' |
include '..\network.inc' |
START: |
mcall 40, EVM_REDRAW + EVM_BUTTON + EVM_STACK2 |
redraw: |
mcall 12, 1 |
mcall 0, 100 shl 16 + 600, 100 shl 16 + 240, 0x34bcbcbc, , name ; draw window |
call draw_interfaces |
mov edx, 101 |
mov esi, 0x00aaaaff |
mov edi, 0x00aaffff |
cmp dl, [mode] |
cmove esi, edi |
mcall 8, 25 shl 16 + 65, 25 shl 16 + 20 |
.morebuttons: |
inc edx |
add ebx, 75 shl 16 |
mov esi, 0x00aaaaff |
cmp dl, [mode] |
cmove esi, edi |
mcall |
cmp edx, 105 |
jle .morebuttons |
mcall 4, 28 shl 16 + 31, 0x80000000, modes |
cmp [mode], 101 |
jne .no_eth |
mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx |
add ebx, 18 |
mov edx, str_packets_rx |
mcall |
add ebx, 18 |
mov edx, str_bytes_tx |
mcall |
add ebx, 18 |
mov edx, str_bytes_rx |
mcall |
add ebx, 18 |
mov edx, str_MAC |
mcall |
add ebx, 18 |
mov edx, str_link |
mcall |
mov ebx, API_ETH + 4 |
mov bh, [device] |
mcall 76 |
push eax |
push bx |
mov edx, 135 shl 16 + 75 + 4*18 |
call draw_mac |
jmp end_of_draw |
.no_eth: |
cmp [mode], 102 |
jne .no_ip |
mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx |
add ebx, 18 |
mov edx, str_packets_rx |
mcall |
add ebx, 18 |
mov edx, str_ip |
mcall |
add ebx, 18 |
mov edx, str_dns |
mcall |
add ebx, 18 |
mov edx, str_subnet |
mcall |
add ebx, 18 |
mov edx, str_gateway |
mcall |
mov ebx, API_IPv4 + 8 |
mov bh, [device] |
mcall 76 |
push eax |
dec bl |
dec bl |
mcall 76 |
push eax |
dec bl |
dec bl |
mcall 76 |
push eax |
dec bl |
dec bl |
mcall 76 |
push eax |
mov edx, 135 shl 16 + 75 + 2*18 |
call draw_ip |
add edx, 18 |
call draw_ip |
add edx, 18 |
call draw_ip |
add edx, 18 |
call draw_ip |
jmp end_of_draw |
.no_ip: |
cmp [mode], 103 |
jne .no_arp |
mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx |
add ebx, 18 |
mov edx, str_packets_rx |
mcall |
add ebx, 18 |
mov edx, str_arp |
mcall |
add ebx, 18 |
mov edx, str_conflicts |
mcall |
jmp end_of_draw |
.no_arp: |
mcall 4, 20 shl 16 + 75, 0x80000000, str_packets_tx |
add ebx, 18 |
mov edx, str_packets_rx |
mcall |
cmp [mode], 106 |
jne end_of_draw |
add ebx, 18 |
mov edx, str_missed |
mcall |
add ebx, 18 |
mov edx, str_dumped |
mcall |
end_of_draw: |
mcall 12, 2 |
draw_stats: |
cmp [mode], 101 |
jne not_101 |
mov ebx, API_ETH |
mov bh, [device] |
@@: |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
cmp bl, 3 |
jbe @r |
inc bl |
mcall 76 |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 5*18 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18*2 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_101: |
cmp [mode], 102 |
jne not_102 |
mov ebx, API_IPv4 |
mov bh, [device] |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 18 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_102: |
cmp [mode], 103 |
jne not_103 |
mov ebx, API_ARP |
mov bh, [device] |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov bl, 7 |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 3*18 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_103: |
cmp [mode], 104 |
jne not_104 |
mov ebx, API_ICMP |
mov bh, [device] |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 18 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_104: |
cmp [mode], 105 |
jne not_105 |
mov ebx, API_UDP |
mov bh, [device] |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 18 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_105: |
cmp [mode], 106 |
jne not_106 |
mov ebx, API_TCP |
mov bh, [device] |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
inc bl |
push ebx |
mcall 76 |
pop ebx |
push eax |
mov ebx, 0x000a0000 |
pop ecx |
mov edx, 135 shl 16 + 75 + 18*3 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mcall 47 |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
sub edx, 18 |
pop ecx |
mcall |
jmp mainloop |
not_106: |
mainloop: |
mcall 23, 50 ; wait for event with timeout (0,5 s) |
cmp eax, 1 |
je redraw |
cmp eax, 3 |
je button |
cmp eax, 11 |
je redraw |
jmp draw_stats |
button: ; button |
mcall 17 ; get id |
cmp ah, 1 |
je exit |
cmp ah, 0 |
je .interface |
mov [mode], ah |
jmp redraw |
.interface: |
shr eax, 16 |
mov [device], al |
jmp redraw |
exit: |
mcall -1 |
draw_mac: |
mov eax, 47 |
mov ebx, 0x00020100 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
mov cl, [esp+4] |
mcall |
mov cl, [esp+4+1] |
add edx, 15 shl 16 |
mcall |
mov cl, [esp+4+2] |
add edx, 15 shl 16 |
mcall |
mov cl, [esp+4+3] |
add edx, 15 shl 16 |
mcall |
mov cl, [esp+4+4] |
add edx, 15 shl 16 |
mcall |
mov cl, [esp+4+5] |
add edx, 15 shl 16 |
mcall |
sub edx, 5*15 shl 16 |
ret 6 |
draw_ip: |
mov eax, 47 |
mov ebx, 0x00030000 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
xor ecx, ecx |
mov cl, [esp+4] |
mcall |
mov cl, [esp+4+1] |
add edx, 30 shl 16 |
mcall |
mov cl, [esp+4+2] |
add edx, 30 shl 16 |
mcall |
mov cl, [esp+4+3] |
add edx, 30 shl 16 |
mcall |
sub edx, 3*30 shl 16 |
ret 4 |
draw_interfaces: |
mov [.btnpos], 8 shl 16 + 20 |
mov [.txtpos], 490 shl 16 + 15 |
mcall 74, -1 ; get number of active network devices |
mov ecx, eax |
xor ebx, ebx ; get device type |
.loop: |
mcall 74 |
cmp eax, 1 ; ethernet? |
je .hit |
inc bh |
jb .loop ; tried all 256? |
ret |
.hit: |
push ecx ebx |
movzx edx, bh |
shl edx, 8 |
mov esi, 0x00aaaaff |
cmp bh, [device] |
cmove esi, 0x00aaffff |
mcall 8, 485 shl 16 + 100, [.btnpos] |
mov ebx, [esp] |
inc bl |
mov ecx, namebuf |
mov edx, namebuf |
mcall 74 ; get device name |
cmp eax, -1 |
jne @f |
mov edx, str_unknown |
@@: |
mcall 4, [.txtpos], 0x80000000 ; print the name |
pop ebx ecx |
inc bh |
add [.btnpos], 25 shl 16 |
add [.txtpos], 25 |
dec ecx |
jnz .loop |
ret |
.btnpos dd ? |
.txtpos dd ? |
; DATA AREA |
name db 'Netstat', 0 |
mode db 101 |
device db 0 |
modes db 'Ethernet IPv4 ARP ICMP UDP TCP', 0 |
str_packets_tx db 'Packets sent:', 0 |
str_packets_rx db 'Packets received:', 0 |
str_bytes_tx db 'Bytes sent:', 0 |
str_bytes_rx db 'Bytes received:', 0 |
str_MAC db 'MAC address:', 0 |
str_ip db 'IP address:', 0 |
str_dns db 'DNS address:', 0 |
str_subnet db 'Subnet mask:', 0 |
str_gateway db 'Standard gateway:', 0 |
str_arp db 'ARP entrys:', 0 |
str_conflicts db 'ARP conflicts:', 0 |
str_unknown db 'unknown', 0 |
str_missed db 'Packets missed:',0 |
str_dumped db 'Packets dumped:',0 |
str_link db 'Link state:',0 |
namebuf rb 64 |
I_PARAM rb 1024 |
I_END: |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/network.inc |
---|
0,0 → 1,94 |
; Socket types |
SOCK_STREAM = 1 |
SOCK_DGRAM = 2 |
SOCK_RAW = 3 |
; Socket options |
SO_NONBLOCK = 1 shl 31 |
; IP protocols |
IPPROTO_IP = 0 |
IPPROTO_ICMP = 1 |
IPPROTO_TCP = 6 |
IPPROTO_UDP = 17 |
; Address families |
AF_UNSPEC = 0 |
AF_LOCAL = 1 |
AF_INET4 = 2 ; IPv4 |
AF_INET6 = 28 ; IPv6 (not supported yet) |
PF_UNSPEC = AF_UNSPEC |
PF_LOCAL = AF_LOCAL |
PF_INET4 = AF_INET4 |
PF_INET6 = AF_INET6 |
; Flags for addrinfo |
AI_PASSIVE = 1 |
AI_CANONNAME = 2 |
AI_NUMERICHOST = 4 |
AI_NUMERICSERV = 8 |
AI_ADDRCONFIG = 0x400 |
; internal definition |
AI_SUPPORTED = 0x40F |
; for system function 76 |
API_ETH = 0 shl 16 |
API_IPv4 = 1 shl 16 |
API_ICMP = 2 shl 16 |
API_UDP = 3 shl 16 |
API_TCP = 4 shl 16 |
API_ARP = 5 shl 16 |
API_PPPOE = 6 shl 16 |
struct sockaddr_in |
sin_family dw ? ; sa_family_t |
sin_port dw ? ; in_port_t |
sin_addr dd ? ; struct in_addr |
sin_zero rb 8 ; zero |
ends |
struct addrinfo |
ai_flags dd ? ; bitmask of AI_* |
ai_family dd ? ; PF_* |
ai_socktype dd ? ; SOCK_* |
ai_protocol dd ? ; 0 or IPPROTO_* |
ai_addrlen dd ? ; length of ai_addr |
ai_canonname dd ? ; char* |
ai_addr dd ? ; struct sockaddr* |
ai_next dd ? ; struct addrinfo* |
ends |
EAI_ADDRFAMILY = 1 |
EAI_AGAIN = 2 |
EAI_BADFLAGS = 3 |
EAI_FAIL = 4 |
EAI_FAMILY = 5 |
EAI_MEMORY = 6 |
EAI_NONAME = 8 |
EAI_SERVICE = 9 |
EAI_SOCKTYPE = 10 |
EAI_BADHINTS = 12 |
EAI_PROTOCOL = 13 |
EAI_OVERFLOW = 14 |
socket fix 75, 0 |
close fix 75, 1 |
bind fix 75, 2 |
listen fix 75, 3 |
connect fix 75, 4 |
accept fix 75, 5 |
send fix 75, 6 |
recv fix 75, 7 |
setsockopt fix 75, 8 |
getsockopt fix 75, 9 |
socketpair fix 75, 10 |
struct ARP_entry |
IP dd ? |
MAC dp ? |
status dw ? |
TTL dw ? |
ends |
/kernel/branches/net/applications/tftpc/tftpc.asm |
---|
0,0 → 1,566 |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' |
dd 0x1 |
dd START |
dd I_END |
dd IM_END |
dd IM_END |
dd 0, 0 |
include '../proc32.inc' |
include '../macros.inc' |
include '../libio.inc' |
include '../dll.inc' |
include '../../../../../programs/develop/libraries/box_lib/trunk/box_lib.mac' |
include '../network.inc' |
filebuffer_size equ 4*4096 ; 16kb (dont try to change it yet..) |
TIMEOUT equ 100 |
buffer_len equ 1500 |
AF_INET4 equ 2 |
IP_PROTO_UDP equ 17 |
opcode_rrq equ 1 |
opcode_wrq equ 2 |
opcode_data equ 3 |
opcode_ack equ 4 |
opcode_error equ 5 |
; read/write request packet |
; |
; 2 bytes string 1 byte string 1 byte |
; ------------------------------------------------ |
; | Opcode | Filename | 0 | Mode | 0 | |
; ------------------------------------------------ |
; data packet |
; |
; 2 bytes 2 bytes n bytes |
; ---------------------------------- |
; | Opcode | Block # | Data | |
; ---------------------------------- |
; acknowledgement packet |
; |
; 2 bytes 2 bytes |
; --------------------- |
; | Opcode | Block # | |
; --------------------- |
; error packet |
; |
; 2 bytes 2 bytes string 1 byte |
; ---------------------------------------- |
; | Opcode | ErrorCode | ErrMsg | 0 | |
; ---------------------------------------- |
START: |
mcall 68, 11 |
stdcall dll.Load, @IMPORT |
or eax, eax |
jnz exit |
stop_transfer: |
mcall 40, 00100111b |
red_win: |
call draw_window |
align 4 |
still: |
mcall 10 |
dec eax |
jz red_win |
dec eax |
jz key |
dec eax |
jz button |
push dword edit1 |
call [edit_box_mouse] |
push dword edit2 |
call [edit_box_mouse] |
push dword edit3 |
call [edit_box_mouse] |
push dword edit4 |
call [edit_box_mouse] |
push dword Option_boxs1 |
call [option_box_mouse] |
push dword Option_boxs2 |
call [option_box_mouse] |
jmp still |
button: |
mcall 17 |
cmp ah,0x10 |
je start_transfer |
test ah , ah |
jz still |
exit: mcall -1 |
key: |
mcall 2 |
push dword edit1 |
call [edit_box_key] |
push dword edit2 |
call [edit_box_key] |
push dword edit3 |
call [edit_box_key] |
push dword edit4 |
call [edit_box_key] |
jmp still |
align 4 |
draw_window: |
mcall 12,1 |
mcall 0, (50*65536+400), (30*65536+180), 0x34AABBCC, 0x085080DD, str_title |
mcall 4, 35*65536+10, 0x80000000, str_server |
mov ebx, 5*65536+30 |
mov edx, str_source |
mcall |
mov ebx, 11*65536+50 |
mov edx, str_destination |
mcall |
mov ebx, 47*65536+72 |
mov edx, str_mode |
mcall |
mov ebx, 160*65536+72 |
mov edx, str_method |
mcall |
mov ebx, 270*65536+72 |
mov edx, str_blocksize |
mcall |
push dword edit1 |
call [edit_box_draw] |
push dword edit2 |
call [edit_box_draw] |
push dword edit3 |
call [edit_box_draw] |
push dword edit4 |
call [edit_box_draw] |
push dword Option_boxs1 |
call [option_box_draw] |
push dword Option_boxs2 |
call [option_box_draw] |
mcall 8,210*65536+170, 105*65536+16,0x00000010,0x085080DD |
mcall 4,260*65536+110, 0x80000000, str_transfer |
mcall 38,10*65536+380, 130*65536+130,0x00000000 |
mcall 4,350*65536+137, 0x80000000, str_kb_s |
mcall 47,1 shl 31 + 7 shl 16 + 1,kbps,305*65536+137,0x00000000 |
mcall 4,50*65536+137, 0x80000000, str_complete |
mcall 47,1 shl 31 + 3 shl 16 + 1,done,25*65536+137,0x00000000 |
mcall 12,2 |
ret |
start_transfer: |
; first, resolve the hostname |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push dword SRV ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz still |
mov esi, [esi] |
mov esi, [esi + sockaddr_in.sin_addr] |
mov dword [IP], esi |
mcall socket, AF_INET4, SOCK_DGRAM, 0 ; socket_open |
cmp eax, -1 |
je still |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr, sockaddr_len ; socket_connect |
cmp eax, -1 |
je still |
mov word [I_END], opcode_rrq |
cmp [option_group2],op3 |
je @f |
mov word [I_END], opcode_wrq |
@@: |
xor al , al |
mov edi, remote_addr |
mov ecx, 250 |
repnz scasb |
sub edi, remote_addr-1 |
mov ecx, edi |
mov edi, I_END+2 |
mov esi, remote_addr |
rep movsb |
cmp [option_group1], op1 |
je .ascii |
mov esi, octet |
movsd |
movsb |
jmp .send_request |
.ascii: |
mov esi, netascii |
movsd |
movsd |
.send_request: |
xor al, al |
stosb |
sub edi, I_END |
mov esi, edi |
mcall send, [socketnum], I_END |
mcall 40, 10000101b |
mov [last_ack], 0 |
receive_data_loop: |
mcall 23, TIMEOUT |
dec eax |
jz .red |
dec eax |
jz .key |
mcall recv, [socketnum], buffer, buffer_len, 0 ; receive data |
cmp word[buffer], opcode_data |
jne .error |
mov bx, [last_ack] |
cmp word [buffer + 2], bx |
jne .packet_got_lost |
inc [last_ack] |
cmp eax, 4+512 |
je .continue |
; last packet, or something else |
.error: |
.packet_got_lost: |
.continue: |
mov word[buffer], opcode_ack ; send ack |
mcall send, [socketnum], buffer, 4, 0 |
jmp receive_data_loop |
.red: |
call draw_window |
jmp receive_data_loop |
.key: |
mcall 2 |
cmp ah, 2 |
jz exit |
; close socket ? |
jmp receive_data_loop |
;-------------------------------- |
send_: |
invoke file_open, local_addr, O_READ |
or eax, eax |
jz .exit |
mov [fh], eax |
stdcall mem.Alloc, filebuffer_size |
or eax, eax |
jz .exit |
mov [fb], eax |
mov [last_ack], 0 |
mov [fo], 0 |
.read_chunk: |
invoke file_seek, [fh], [fo], SEEK_END |
cmp eax, -1 |
je .exit |
invoke file_read, [fh], [fb], filebuffer_size |
cmp eax, -1 |
je .exit |
add [fo], filebuffer_size |
cmp eax, filebuffer_size |
je .packet |
; ijhidfhfdsndsfqk |
.packet: |
movzx esi, [last_ack] |
and esi, 0x000000001f ; last five bits BUFFER SIZE MUST BE 16 kb for this to work !!! |
shl esi, 9 ; = * 512 |
add esi, [fb] |
mov edi, buffer |
mov ax, opcode_data |
stosw |
mov ax, [last_ack] |
stosw |
mov ecx, 512/4 |
rep movsd |
mcall send, [socketnum], buffer, 4+512, 0 ; send data |
.loop: |
mcall 23, TIMEOUT |
dec eax |
jz .red |
dec eax |
jz .key |
mcall recv, [socketnum], buffer, buffer_len, 0 ; receive ack |
cmp word[buffer], opcode_ack |
jne .exit |
mov ax, [last_ack] |
cmp word[buffer+2], ax |
jne .packet |
inc [last_ack] |
test [last_ack],0x001f |
jz .read_chunk |
jmp .packet |
.red: |
call draw_window |
jmp .loop |
.key: |
mcall 2 |
cmp ah, 2 |
jz exit |
; close socket ? |
jmp .loop |
.exit: |
invoke file_close, [fh] |
jmp still |
;------------------------- |
; DATA |
socketnum dd 0 |
kbps dd 0 |
done dd 0 |
sockaddr: |
dw AF_INET4 |
dw 0x4500 ; 69 |
IP db 192,168,1,115 |
sockaddr_len = $ - sockaddr |
align 16 |
@IMPORT: |
library box_lib , 'box_lib.obj', \ |
io_lib , 'libio.obj', \ |
network , 'network.obj' |
import box_lib ,\ |
edit_box_draw ,'edit_box' ,\ |
edit_box_key ,'edit_box_key' ,\ |
edit_box_mouse ,'edit_box_mouse' ,\ |
version_ed ,'version_ed' ,\ |
init_checkbox ,'init_checkbox2' ,\ |
check_box_draw ,'check_box_draw2' ,\ |
check_box_mouse ,'check_box_mouse2' ,\ |
version_ch ,'version_ch2' ,\ |
option_box_draw ,'option_box_draw' ,\ |
option_box_mouse ,'option_box_mouse' ,\ |
version_op ,'version_op' |
import io_lib ,\ |
file_find_first , 'file_find_first' ,\ |
file_find_next , 'file_find_next' ,\ |
file_find_close , 'file_find_close' ,\ |
file_size , 'file_size' ,\ |
file_open , 'file_open' ,\ |
file_read , 'file_read' ,\ |
file_write , 'file_write' ,\ |
file_seek , 'file_seek' ,\ |
file_tell , 'file_tell' ,\ |
file_eof? , 'file_iseof' ,\ |
file_seteof , 'file_seteof' ,\ |
file_truncate , 'file_truncate' ,\ |
file_close , 'file_close' |
import network ,\ |
inet_ntoa , 'inet_ntoa' ,\ |
getaddrinfo , 'getaddrinfo' ,\ |
freeaddrinfo , 'freeaddrinfo' |
edit1 edit_box 300,80,5 ,0xffffff,0x6f9480,0,0,0,99 ,SRV,mouse_dd,ed_focus, 11,11 |
edit2 edit_box 300,80,25,0xffffff,0x6a9480,0,0,0,99 ,remote_addr,mouse_dd,ed_figure_only, 5,5 |
edit3 edit_box 300,80,45,0xffffff,0x6a9480,0,0,0,99 ,local_addr,mouse_dd,ed_figure_only, 27,27 |
edit4 edit_box 40,340,68,0xffffff,0x6a9480,0,0,0,5 ,BLK,mouse_dd,ed_figure_only, 3,3 |
op1 option_box option_group1,80,68,6,12,0xffffff,0,0,netascii,octet-netascii |
op2 option_box option_group1,80,85,6,12,0xFFFFFF,0,0,octet,get-octet |
op3 option_box option_group2,210,68,6,12,0xffffff,0,0,get,put-get |
op4 option_box option_group2,210,85,6,12,0xFFFFFF,0,0,put,BLK-put |
option_group1 dd op1 |
option_group2 dd op3 |
Option_boxs1 dd op1,op2,0 |
Option_boxs2 dd op3,op4,0 |
str_title db 'TFTP client for KolibriOS',0 |
str_server db 'Server:',0 |
str_source db 'Remote file:',0 |
str_destination db 'Local file:',0 |
str_mode db 'Mode:',0 |
str_method db 'Method:',0 |
str_blocksize db 'Blocksize:',0 |
str_kb_s db 'kb/s',0 |
str_complete db '% complete',0 |
str_transfer db 'Transfer',0 |
str_error: |
._0 db 'Not defined, see error message (if any).',0 |
._1 db 'File not found.',0 |
._2 db 'Access violation.',0 |
._3 db 'Disk full or allocation exceeded.',0 |
._4 db 'Illegal TFTP operation.',0 |
._5 db 'Unknown transfer ID.',0 |
._6 db 'File already exists.',0 |
._7 db 'No such user.',0 |
netascii db 'NetASCII' |
octet db 'Octet' |
get db 'GET' |
put db 'PUT' |
BLK db "512",0,0,0 |
last_ack dw ? |
fh dd ? ; file handle |
fo dd ? ; file offset |
fb dd ? ; file buffer |
SRV db "192.168.1.115",0 |
rb (SRV + 256 - $) |
remote_addr db "IMG00",0 |
rb (remote_addr + 256 - $) |
local_addr db "/hd0/1/KolibriOS/kernel.mnt",0 |
rb (local_addr + 256 - $) |
I_END: |
mouse_dd dd ? |
buffer: |
rb buffer_len |
rb 0x1000 ; stack |
IM_END: |
/kernel/branches/net/applications/socketdbg/socket.inc |
---|
0,0 → 1,164 |
struct LHEAD |
next dd ? ;next object in list |
prev dd ? ;prev object in list |
ends |
struct MUTEX |
lhead LHEAD |
count dd ? |
ends |
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 ? ; application process id |
Domain dd ? ; INET/UNIX/.. |
Type dd ? ; RAW/STREAM/DGRAP |
Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP |
errorcode dd ? |
device dd ? |
options dd ? |
state dd ? |
backlog dw ? ; how many incomming connections that can be queued |
snd_proc dd ? |
rcv_proc dd ? |
ends |
struct IP_SOCKET SOCKET |
LocalIP rd 4 ; network byte order |
RemoteIP rd 4 ; network byte order |
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_force 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 ? ; window minus one |
SND_WL2 dd ? ; |
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 ? |
SND_SSTHRESH dd ? |
;---------------------- |
; Transmit timing stuff |
t_idle dd ? |
t_rtt dd ? |
t_rtseq dd ? |
t_srtt dd ? |
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_retransmission dd ? ; rexmt |
timer_persist dd ? |
timer_keepalive dd ? ; keepalive/syn timeout |
timer_timed_wait dd ? ; also used as 2msl timer |
; extra |
ts_ecr dd ? ; timestamp echo reply |
ts_val dd ? |
temp_bits db ? |
ends |
struct UDP_SOCKET IP_SOCKET |
LocalPort dw ? ; network byte order |
RemotePort dw ? ; network byte order |
firstpacket db ? |
ends |
struct ICMP_SOCKET IP_SOCKET |
Identifier dw ? |
ends |
struct RING_BUFFER |
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 |
/kernel/branches/net/applications/socketdbg/socketdbg.asm |
---|
0,0 → 1,100 |
format binary as "" |
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd 0 ; parameters |
dd 0 ; path |
; useful includes |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../struct.inc' |
include 'socket.inc' |
; entry point |
start: |
mcall 40, 0 ; we dont want any events |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push -1 |
push -1 |
push -1 |
push -1 |
call [con_init] |
; main loop |
main: |
mcall 75, 255, 0, socket_list ; get current socket list |
call [con_cls] |
mov esi, socket_list |
.loop: |
lodsd |
test eax, eax |
jz .done |
mov ecx, eax |
mcall 75, 255, , socket_buf |
pushd [socket_buf + SOCKET.state] |
pushd [socket_buf + SOCKET.PID] |
pushd [socket_buf + SOCKET.Number] |
push str_sock |
call [con_printf] |
add esp, 4 |
jmp .loop |
.done: |
mcall 23, 50 |
jmp main |
push 0 |
call [con_exit] |
exit: |
mcall -1 |
; data |
title db 'Socket debugger', 0 |
str_sock db 'Socket=%d PID=%d state=%d', 10, 0 |
; import |
align 4 |
@IMPORT: |
library console, 'console.obj' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_cls, 'con_cls', \ |
con_exit, 'con_exit', \ |
con_printf, 'con_printf' |
i_end: |
socket_list rd 4096 |
socket_buf rd 4096 |
align 4 |
rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/ftpd/commands.inc |
---|
0,0 → 1,1135 |
struct thread_data |
rb 1024 |
stack rb 0 |
home_dir rb 1024 ; home directory in wich the user is locked, asciiz |
work_dir rb 1024 ; working directory, must at all times begin and end with a '/', asciiz |
fpath rb 1024*3 ; file path, combination of home_dir, work_dir and filename |
; Will also be used to temporarily store username |
type db ? ; ASCII/EBDIC/IMAGE/.. |
mode db ? ; active/passive |
socketnum dd ? ; Commands socket |
state dd ? ; disconnected/logging in/logged in/.. |
passivesocknum dd ? ; when in passive mode, this is the listening socket |
datasocketnum dd ? ; socket used for data transfers |
permissions dd ? ; read/write/execute/.... |
buffer_ptr dd ? |
pid dd ? ; Process id of the current thread |
datasock sockaddr_in |
buffer rb BUFFERSIZE |
ends |
;------------------------------------------------ |
; parse_cmd |
; |
; Internal function wich uses the 'commands' |
; table to call an appropriate cmd_xx function. |
; |
; input: esi = ptr to ascii commands |
; ecx = number of bytes input |
; ebp = pointer to thread_data structure |
; |
; output: none |
; |
;------------------------------------------------ |
align 4 |
parse_cmd: ; esi must point to command |
cmp byte [esi], 0x20 ; skip all leading characters |
ja .ok |
inc esi |
dec ecx |
cmp ecx, 3 |
jb .error |
jmp parse_cmd |
.ok: |
cmp byte [esi+3], 0x20 |
ja @f |
mov byte [esi+3], 0 |
@@: |
mov eax, [esi] |
and eax, not 0x20202020 ; convert to upper case |
mov edi, commands ; list of commands to scan |
.scanloop: |
cmp eax, [edi] |
je .got_it |
add edi, 5*4 |
cmp byte [edi], 0 |
jne .scanloop |
.error: |
cmp [ebp + thread_data.state], STATE_ACTIVE |
jb login_first |
sendFTP "500 Unsupported command" |
ret |
.got_it: |
mov eax, [ebp + thread_data.state] |
jmp dword [edi + 4 + eax] |
align 4 |
iglobal |
commands: ; all commands must be in uppercase |
dd 'ABOR', login_first, login_first, login_first, cmdABOR |
; dd 'ACCT', login_first, login_first, login_first, cmd_ACCT |
; dd 'APPE', login_first, login_first, login_first, cmd_APPE |
dd 'CDUP', login_first, login_first, login_first, cmdCDUP |
dd 'CWD', login_first, login_first, login_first, cmdCWD |
dd 'DELE', login_first, login_first, login_first, cmdDELE |
; dd 'HELP', login_first, login_first, login_first, cmd_HELP |
dd 'LIST', login_first, login_first, login_first, cmdLIST |
; dd 'MDTM', login_first, login_first, login_first, cmd_MDTM |
; dd 'MKD', login_first, login_first, login_first, cmd_MKD |
; dd 'MODE', login_first, login_first, login_first, cmd_MODE |
dd 'NLST', login_first, login_first, login_first, cmdNLST |
dd 'NOOP', login_first, login_first, login_first, cmdNOOP |
dd 'PASS', cmdPASS.0, cmdPASS , cmdPASS.2, cmdPASS.3 |
dd 'PASV', login_first, login_first, login_first, cmdPASV |
dd 'PORT', login_first, login_first, login_first, cmdPORT |
dd 'PWD', login_first, login_first, login_first, cmdPWD |
dd 'QUIT', cmdQUIT, cmdQUIT, cmdQUIT, cmdQUIT |
; dd 'REIN', login_first, login_first, login_first, cmd_REIN |
; dd 'REST', login_first, login_first, login_first, cmd_REST |
dd 'RETR', login_first, login_first, login_first, cmdRETR |
; dd 'RMD', login_first, login_first, login_first, cmd_RMD |
; dd 'RNFR', login_first, login_first, login_first, cmd_RNFR |
; dd 'RNTO', login_first, login_first, login_first, cmd_RNTO |
; dd 'SITE', login_first, login_first, login_first, cmd_SITE |
; dd 'SIZE', login_first, login_first, login_first, cmd_SIZE |
; dd 'STAT', login_first, login_first, login_first, cmd_STAT |
dd 'STOR', login_first, login_first, login_first, cmdSTOR |
; dd 'STOU', login_first, login_first, login_first, cmd_STOU |
; dd 'STRU', login_first, login_first, login_first, cmd_STRU |
dd 'SYST', login_first, login_first, login_first, cmdSYST |
dd 'TYPE', login_first, login_first, login_first, cmdTYPE |
dd 'USER', cmdUSER, cmdUSER, cmdUSER, cmdUSER.2 |
db 0 ; end marker |
endg |
align 4 |
login_first: |
sendFTP "530 Please login with USER and PASS" |
ret |
align 4 |
permission_denied: |
sendFTP "550 Permission denied" |
ret |
align 4 |
socketerror: |
invoke con_set_flags, 0x0c |
invoke con_write_asciiz, str_sockerr |
invoke con_set_flags, 0x07 |
sendFTP "425 Can't open data connection" |
ret |
align 4 |
abort_transfer: |
and [ebp + thread_data.permissions], not ABORT |
mov [ebp + thread_data.mode], MODE_NOTREADY |
invoke file.close, ebx |
mcall close, [ebp + thread_data.datasocketnum] |
sendFTP "530 Transfer aborted" |
ret |
align 4 |
ip_to_dword: ; esi = ptr to str, cl = separator ('.', ',') |
call ascii_to_byte |
mov bl, al |
cmp byte [esi], cl |
jne .err |
inc esi |
call ascii_to_byte |
mov bh, al |
cmp byte [esi], cl |
jne .err |
inc esi |
shl ebx, 16 |
call ascii_to_byte |
mov bl, al |
cmp byte [esi], cl |
jne .err |
inc esi |
call ascii_to_byte |
mov bh, al |
ror ebx, 16 |
ret |
.err: |
xor ebx, ebx |
ret |
align 4 ; esi = ptr to str, output in eax |
ascii_to_byte: |
xor eax, eax |
push ebx |
.loop: |
movzx ebx, byte[esi] |
sub bl, '0' |
jb .done |
cmp bl, 9 |
ja .done |
lea eax, [eax*4 + eax] ; |
shl eax, 1 ; eax = eax * 10 |
add eax, ebx |
inc esi |
jmp .loop |
.done: |
pop ebx |
ret |
align 4 |
dword_to_ascii: ; edi = ptr where to write, eax is number |
push edx ebx ecx |
mov ebx, 10 |
xor ecx, ecx |
@@: |
xor edx, edx |
div ebx |
add edx, '0' |
pushw dx |
inc ecx |
test eax, eax |
jnz @r |
@@: |
popw ax |
stosb |
dec ecx |
jnz @r |
pop ecx ebx edx |
ret |
align 4 |
create_path: ; combine home_dir and work_dir strings into fpath |
lea edi, [ebp + thread_data.fpath] |
lea esi, [ebp + thread_data.home_dir] |
mov ecx, 1024 |
.loop1: |
lodsb |
cmp al, 0x20 |
jb .next |
stosb |
loop .loop1 |
.next: |
cmp byte[edi-1], '/' |
jne @f |
dec edi |
@@: |
lea esi, [ebp + thread_data.work_dir] |
mov ecx, 1024 |
.loop2: |
lodsb |
cmp al, 0x20 |
jb .done |
stosb |
loop .loop2 |
.done: |
xor al, al |
stosb |
ret |
align 4 |
nextpasvport: |
inc [pasv_port] |
mov ax, [pasv_port] |
cmp ax, [pasv_start] |
jb .restart |
cmp ax, [pasv_end] |
ja .restart |
ret |
.restart: |
pushw [pasv_start] |
popw [pasv_port] |
ret |
align 4 |
open_datasock: |
cmp [ebp + thread_data.mode], MODE_PASSIVE_OK |
je .start |
; If we are in active mode, it's time to open a data socket.. |
cmp [ebp + thread_data.mode], MODE_ACTIVE |
jne .not_active |
mov ecx, [ebp + thread_data.datasocketnum] |
lea edx, [ebp + thread_data.datasock] |
mov esi, sizeof.thread_data.datasock |
mcall connect |
cmp eax, -1 |
jne .start |
.socketerror: |
add esp, 4 |
jmp socketerror |
; If we are still in passive_wait, it's time we accept an incomming call.. |
.not_active: |
cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT |
jne .socketerror |
.try_now: |
mov ecx, [ebp + thread_data.passivesocknum] |
lea edx, [ebp + thread_data.datasock] |
mov esi, sizeof.thread_data.datasock |
mcall accept |
cmp eax, -1 |
jne .pasv_ok |
mov [ebp + thread_data.mode], MODE_PASSIVE_FAILED ; assume that we will fail |
mcall 23, 200 |
mcall accept |
cmp eax, -1 |
je .socketerror |
.pasv_ok: |
mov [ebp + thread_data.datasocketnum], eax |
mov [ebp + thread_data.mode], MODE_PASSIVE_OK |
mcall close ; [ebp + thread_data.passivesocknum] |
mov [ebp + thread_data.passivesocknum], -1 |
invoke con_write_asciiz, str_datasock |
.start: |
ret |
;------------------------------------------------ |
; "ABOR" |
; |
; This command aborts the current filetransfer. |
; |
;------------------------------------------------ |
align 4 |
cmdABOR: |
or [ebp + thread_data.permissions], ABORT |
sendFTP "250 Command succesul" |
ret |
;------------------------------------------------ |
; "CDUP" |
; |
; Change the directory to move up one level. |
; |
;------------------------------------------------ |
align 4 |
cmdCDUP: |
test [ebp + thread_data.permissions], PERMISSION_CD |
jz permission_denied |
cmp byte [ebp + thread_data.work_dir+1], 0 ; are we in "/" ? |
je .done ; if so, we cant go up.. |
; find the end of asciiz string work_dir |
mov ecx, 1024 |
xor al, al |
lea edi, [ebp + thread_data.work_dir] |
repne scasb |
; return 2 characters (right before last /) |
sub edi, 3 |
; and now search backwards, for a '/' |
mov al,'/' |
neg ecx |
add ecx, 1024 |
std |
repne scasb |
cld |
; terminate the string here |
mov byte[edi+2], 0 |
.done: |
; Print the new working dir on the console |
lea eax, [ebp + thread_data.work_dir] |
invoke con_write_asciiz, eax |
invoke con_write_asciiz, str_newline |
sendFTP "250 Command succesul" |
ret |
;------------------------------------------------ |
; "CWD" |
; |
; Change Working Directory. |
; |
;------------------------------------------------ |
align 4 |
cmdCWD: |
test [ebp + thread_data.permissions], PERMISSION_CD |
jz permission_denied |
; do we have enough parameters? |
sub ecx, 4 |
jbe .err |
; get ready to copy the path |
add esi, 4 |
mov ecx, 1024 |
lea edi, [ebp + thread_data.work_dir] |
; if received dir starts with '/', we will simply copy it |
; If not, we will append the current path with the received path. |
cmp byte [esi], '/' |
je .copyloop |
; Find the end of work_dir string. |
xor al, al |
.find_zero: |
repne scasb |
dec edi |
; and now append work_dir with received string |
mov ecx, 1024 |
; scan for end byte, or '.' |
.copyloop: |
lodsb |
cmp al, 0x20 |
jb .done |
;;; cmp al, '.' ; '..' means we must go up one dir TODO |
;;; je .up |
stosb |
loop .copyloop |
; now, now make sure it ends with '/', 0 |
.done: |
cmp byte [edi-1], '/' |
je @f |
mov byte [edi], '/' |
inc edi |
@@: |
mov byte [edi], 0 |
; Print the new working dir on the console |
lea eax, [ebp + thread_data.work_dir] |
invoke con_write_asciiz, eax |
invoke con_write_asciiz, str_newline |
sendFTP "250 Command succesful" |
ret |
.err: |
sendFTP "550 Directory does not exist" |
ret |
;------------------------------------------------ |
; "DELE" |
; |
; Delete a file from the server. |
; |
;------------------------------------------------ |
align 4 |
cmdDELE: |
test [ebp + thread_data.permissions], PERMISSION_DELETE |
jz permission_denied |
ret |
;------------------------------------------------ |
; "LIST" |
; |
; List the files in the current working directory. |
; |
;------------------------------------------------ |
align 4 |
cmdLIST: |
test [ebp + thread_data.permissions], PERMISSION_EXEC |
jz permission_denied |
call open_datasock |
; Create fpath from home_dir and work_dir |
call create_path |
lea ebx, [ebp + thread_data.fpath] |
invoke con_write_asciiz, ebx |
invoke con_write_asciiz, str_newline |
; Start the search |
invoke file.find.first, ebx, str_mask, FA_READONLY+FA_FOLDER+FA_ARCHIVED;+FA_NORMAL |
test eax, eax |
jz .nosuchdir |
lea edi, [ebp + thread_data.buffer] |
.parse_file: |
test eax, eax ; did we find a file? |
jz .done |
mov ebx, eax ; yes, save the descripter in ebx |
; first, convert the attributes |
test [ebx + FileInfoA.Attributes], FA_FOLDER |
jnz .folder |
test [ebx + FileInfoA.Attributes], FA_READONLY |
jnz .readonly |
mov eax, '-rw-' |
stosd |
jmp .attr |
.folder: |
mov eax, 'drwx' |
stosd |
jmp .attr |
.readonly: |
mov eax, '-r--' |
stosd |
.attr: |
mov eax, 'rw-r' |
stosd |
mov ax, 'w-' |
stosw |
mov al, ' ' |
stosb |
; now.. |
mov ax, '1 ' |
stosw |
; now write owner, everything is owned by FTP, woohoo! |
mov eax, 'FTP ' |
stosd |
stosd |
; now the filesize in ascii |
mov eax, [ebx + FileInfoA.FileSizeLow] |
call dword_to_ascii |
mov al, ' ' |
stosb |
; then date (month/day/year) |
movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.month] |
cmp eax, 12 |
ja @f |
mov eax, [months - 4 + 4*eax] |
stosd |
@@: |
movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.day] |
call dword_to_ascii |
mov al, ' ' |
stosb |
movzx eax, [ebx + FileInfoA.DateModify + FileDateTime.year] |
call dword_to_ascii |
mov al, ' ' |
stosb |
; and last but not least, filename |
lea esi, [ebx + FileInfoA.FileName] |
mov ecx, 264 |
.nameloop: |
lodsb |
test al, al |
jz .namedone |
stosb |
loop .nameloop |
; insert a cr lf |
.namedone: |
mov ax, 0x0a0d |
stosw |
test [ebp + thread_data.permissions], ABORT ; Did we receive ABOR command from client? |
jnz abort_transfer |
; check next file |
invoke file.find.next, ebx |
jmp .parse_file |
; close file desc |
.done: |
invoke file.find.close, ebx ; ebx is descriptor of last file, eax will be -1 !! |
; append the string with a 0 |
xor al, al |
stosb |
; Warn the client we're about to send the data |
push edi |
sendFTP "150 Here it comes.." |
pop esi |
; and send it to the client |
mov ecx, [ebp + thread_data.datasocketnum] ; socket num |
lea edx, [ebp + thread_data.buffer] ; buffer ptr |
sub esi, edx ; length |
xor edi, edi ; flags |
mcall send |
; close the data socket.. |
mov [ebp + thread_data.mode], MODE_NOTREADY |
mcall close, [ebp + thread_data.datasocketnum] |
sendFTP "226 Transfer OK" |
ret |
.nosuchdir: |
sendFTP "550 Directory does not exist" |
ret |
;------------------------------------------------ |
; "NLST" |
; |
; List the filenames of the files in the current working directory. |
; |
;------------------------------------------------ |
align 4 |
cmdNLST: |
test [ebp + thread_data.permissions], PERMISSION_EXEC |
jz permission_denied |
; TODO: same as list but simpler output format |
ret |
;------------------------------------------------ |
; "NOOP" |
; |
; No operation, just keep the connection alive. |
; |
;------------------------------------------------ |
align 4 |
cmdNOOP: |
sendFTP "200 Command OK" |
ret |
;------------------------------------------------ |
; "PASS" |
; |
; Second phase of login process, client provides password. |
; |
;------------------------------------------------ |
align 4 |
cmdPASS: |
; read the password from users.ini |
lea edi, [ebp + thread_data.buffer + 512] ; temp pass |
lea ebx, [ebp + thread_data.fpath] ; temp username |
invoke ini.get_str, path2, ebx, str_pass, edi, 512, str_infinity |
test eax, eax ; unable to read password? fail! |
jnz .incorrect |
cmp dword [edi], -1 ; no key, section or file found.. fail! |
je .incorrect |
cmp byte [edi], 0 ; zero password? ok! |
je .ok |
add esi, 5 |
sub ecx, 5 |
jbe .incorrect ; no password given? but hey, we need one! fail.. |
; compare with received password |
repe cmpsb |
cmp byte [esi-1], 0x20 ; printeable characters left? |
jae .incorrect |
cmp byte [edi-1], 0 |
jne .incorrect |
.ok: |
invoke ini.get_int, path2, ebx, str_mode, 0 |
mov [ebp + thread_data.permissions], eax |
invoke con_write_asciiz, str_pass_ok |
mov [ebp + thread_data.state], STATE_ACTIVE |
sendFTP "230 You are now logged in" |
ret |
.2: |
.incorrect: |
invoke con_write_asciiz, str_pass_err |
mov [ebp + thread_data.state], STATE_CONNECTED ; reset state |
sendFTP "530 Login incorrect" |
ret |
.0: |
sendFTP "503 Login with USER first" |
ret |
.3: |
sendFTP "230 Already logged in" |
ret |
;------------------------------------------------ |
; "PASV" |
; |
; Initiate a passive dataconnection. |
; |
;------------------------------------------------ |
align 4 |
cmdPASV: |
; cmp [ebp + thread_data.passivesocknum], -1 |
; je @f |
; mcall close, [ebp + thread_data.passivesocknum] ; if there is still a socket open, close it |
; @@: |
; Open a new TCP socket |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je socketerror |
mov [ebp + thread_data.passivesocknum], eax |
; Bind it to a known local port |
mov [ebp + thread_data.datasock.sin_family], AF_INET4 |
mov [ebp + thread_data.datasock.sin_addr], 0 |
mov ecx, eax ; passivesocketnum |
lea edx, [ebp + thread_data.datasock] |
mov esi, sizeof.thread_data.datasock |
.next_port: ; TODO: break the endless loop |
call nextpasvport |
mov ax, [pasv_port] |
xchg al, ah |
mov [ebp + thread_data.datasock.sin_port], ax |
mcall bind |
cmp eax, -1 |
je .next_port |
; And set it to listen! |
mcall listen, , 1 |
cmp eax, -1 |
je socketerror |
; Tell our thread we are ready to accept incoming calls |
mov [ebp + thread_data.mode], MODE_PASSIVE_WAIT |
; Now tell the client where to connect to in this format: |
; 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2) |
; where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number. |
; '227 (' |
lea edi, [ebp + thread_data.buffer] |
mov eax, '227 ' |
stosd |
mov al, '(' |
stosb |
; ip |
movzx eax, byte [serverip] |
call dword_to_ascii |
mov al, ',' |
stosb |
movzx eax, byte [serverip+1] |
call dword_to_ascii |
mov al, ',' |
stosb |
movzx eax, byte [serverip+2] |
call dword_to_ascii |
mov al, ',' |
stosb |
movzx eax, byte [serverip+3] |
call dword_to_ascii |
mov al, ',' |
stosb |
; port |
movzx eax, byte [ebp + thread_data.datasock.sin_port] |
call dword_to_ascii |
mov al, ',' |
stosb |
movzx eax, byte [ebp + thread_data.datasock.sin_port+1] |
call dword_to_ascii |
; ')', 13, 10, 0 |
mov eax, ')' + 0x000a0d00 |
stosd |
lea esi, [edi - thread_data.buffer] |
sub esi, ebp |
mov ecx, [ebp + thread_data.socketnum] |
lea edx, [ebp + thread_data.buffer] |
xor edi, edi |
mcall send |
ret |
;------------------------------------------------ |
; "PWD" |
; |
; Print the current working directory. |
; |
;------------------------------------------------ |
align 4 |
cmdPWD: |
mov dword [ebp + thread_data.buffer], '257 ' |
mov byte [ebp + thread_data.buffer+4], '"' |
lea edi, [ebp + thread_data.buffer+5] |
lea esi, [ebp + thread_data.work_dir] |
mov ecx, 1024 |
.loop: |
lodsb |
or al, al |
jz .ok |
stosb |
dec ecx |
jnz .loop |
.ok: |
mov dword [edi], '"' + 0x000a0d00 ; '"',13,10,0 |
lea esi, [edi - thread_data.buffer + 4] |
sub esi, ebp |
mov ecx, [ebp + thread_data.socketnum] |
lea edx, [ebp + thread_data.buffer] |
xor edi, edi |
mcall send |
; Print the new working dir on the console |
lea eax, [ebp + thread_data.work_dir] |
invoke con_write_asciiz, eax |
invoke con_write_asciiz, str_newline |
ret |
;------------------------------------------------ |
; "PORT" |
; |
; Initiate an active dataconnection. |
; |
;------------------------------------------------ |
align 4 |
cmdPORT: |
; PORT a1,a2,a3,a4,p1,p2 |
; IP address a1.a2.a3.a4, port p1*256+p2 |
; Convert the IP |
lea esi, [esi+5] |
mov cl, ',' |
call ip_to_dword |
; And put it in datasock |
mov [ebp + thread_data.datasock.sin_addr], ebx |
; Now the same with portnumber |
inc esi |
call ascii_to_byte |
mov byte[ebp + thread_data.datasock.sin_port], al |
inc esi |
call ascii_to_byte |
mov byte[ebp + thread_data.datasock.sin_port+1], al |
; We will open the socket, but do not connect yet! |
mov [ebp + thread_data.datasock.sin_family], AF_INET4 |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je socketerror |
mov [ebp + thread_data.datasocketnum], eax |
mov [ebp + thread_data.mode], MODE_ACTIVE |
sendFTP "225 Data connection open" |
ret |
;------------------------------------------------ |
; "QUIT" |
; |
; Close the connection with client. |
; |
;------------------------------------------------ |
align 4 |
cmdQUIT: |
sendFTP "221 Bye!" |
mcall close, [ebp + thread_data.datasocketnum] |
mcall close, [ebp + thread_data.socketnum] |
add esp, 4 ; get rid of call return address |
jmp thread_exit ; now close this thread |
;------------------------------------------------ |
; "RETR" |
; |
; Retrieve a file from the ftp server. |
; |
;------------------------------------------------ |
align 4 |
cmdRETR: |
test [ebp + thread_data.permissions], PERMISSION_READ |
jz permission_denied |
cmp ecx, 1024 + 5 |
jae .cannot_open |
sub ecx, 5 |
jb .cannot_open |
call open_datasock |
call create_path |
dec edi |
lea esi, [ebp + thread_data.buffer + 5] |
mov ecx, 1024 |
cmp byte [esi], '/' |
jne .loop |
inc esi |
.loop: |
lodsb |
cmp al, 0x20 |
jl .done |
stosb |
loop .loop |
.done: |
xor al, al |
stosb |
lea ebx, [ebp + thread_data.fpath] |
invoke con_write_asciiz, ebx |
invoke con_write_asciiz, str_newline |
invoke file.open, ebx, O_READ |
test eax, eax |
jz .cannot_open |
push eax |
sendFTP "150 Here it comes.." |
pop ebx |
.read_more: |
test [ebp + thread_data.permissions], ABORT |
jnz abort_transfer |
lea eax, [ebp + thread_data.buffer] ; FIXME: use another buffer!! if we receive something on control connection now, we screw up! |
invoke file.read, ebx, eax, BUFFERSIZE |
cmp eax, -1 |
je .cannot_open ; FIXME: this is not the correct error |
invoke con_write_asciiz, str2 |
push eax ebx |
mov esi, eax |
mov ecx, [ebp + thread_data.datasocketnum] |
lea edx, [ebp + thread_data.buffer] |
xor edi, edi |
mcall send |
pop ebx ecx |
cmp eax, -1 |
je socketerror ; FIXME: not the correct error |
; cmp eax, ecx |
; jne not_all_byes_sent ; TODO |
cmp ecx, BUFFERSIZE |
je .read_more |
invoke file.close, ebx |
invoke con_write_asciiz, str2b |
mov [ebp + thread_data.mode], MODE_NOTREADY |
mcall close, [ebp + thread_data.datasocketnum] |
sendFTP "226 Transfer OK, closing connection" |
ret |
.cannot_open: |
invoke con_set_flags, 0x0c |
invoke con_write_asciiz, str_notfound |
invoke con_set_flags, 0x07 |
sendFTP "550 No such file" |
ret |
;------------------------------------------------ |
; "STOR" |
; |
; Store a file on the server. |
; |
;------------------------------------------------ |
align 4 |
cmdSTOR: |
test [ebp + thread_data.permissions], PERMISSION_WRITE |
jz permission_denied |
;;;; |
test [ebp + thread_data.permissions], ABORT |
jnz abort_transfer |
;;;; |
ret |
;------------------------------------------------ |
; "SYST" |
; |
; Send information about the system. |
; |
;------------------------------------------------ |
align 4 |
cmdSYST: |
sendFTP "215 UNIX type: L8" |
ret |
;------------------------------------------------ |
; "TYPE" |
; |
; Choose the file transfer type. |
; |
;------------------------------------------------ |
align 4 |
cmdTYPE: |
cmp ecx, 6 |
jb parse_cmd.error |
mov al, byte[esi+5] |
and al, not 0x20 |
cmp al, 'A' |
je .ascii |
cmp al, 'E' |
je .ebdic |
cmp al, 'I' |
je .image |
cmp al, 'L' |
je .local |
jmp parse_cmd.error |
.ascii: |
mov [ebp + thread_data.type], TYPE_ASCII |
jmp .subtype |
.ebdic: |
mov [ebp + thread_data.type], TYPE_EBDIC |
.subtype: |
cmp ecx, 8 |
jb .non_print |
mov al, byte[esi+7] |
and al, not 0x20 |
cmp al, 'N' |
je .non_print |
cmp al, 'T' |
je .telnet |
cmp al, 'C' |
je .asacc |
cmp al, 0x20 |
jb .non_print |
jmp parse_cmd.error |
.non_print: |
or [ebp + thread_data.type], TYPE_NP |
jmp .ok |
.telnet: |
or [ebp + thread_data.type], TYPE_TELNET |
jmp .ok |
.asacc: |
or [ebp + thread_data.type], TYPE_ASA |
jmp .ok |
.image: |
mov [ebp + thread_data.type], TYPE_IMAGE |
jmp .ok |
.local: |
cmp ecx, 8 |
jb parse_cmd.error |
mov al, byte[esi+7] |
sub al, '0' |
jb parse_cmd.error ; FIXME: this is not the correct errormessage |
cmp al, 9 |
ja parse_cmd.error ; FIXME |
or al, TYPE_LOCAL |
mov [ebp + thread_data.type], al |
.ok: |
sendFTP "200 Command ok" |
ret |
;------------------------------------------------ |
; "USER" |
; |
; Login to the server, step one of two. ;;; TODO: prevent buffer overflow! |
; |
;------------------------------------------------ |
align 4 |
cmdUSER: |
lea esi, [esi + 5] |
lea edi, [ebp + thread_data.fpath] ; temp buffer for username |
.loop: |
lodsb |
stosb |
cmp al, 0x20 |
jae .loop |
mov byte [edi-1], 0 |
lea esi, [ebp + thread_data.fpath] |
lea eax, [ebp + thread_data.home_dir] |
invoke ini.get_str, path2, esi, str_home, eax, 1024, str_infinity |
cmp eax, -1 |
je .login_fail |
cmp dword [esi], -1 |
je .login_fail |
mov word [ebp + thread_data.work_dir], "/" ; "/", 0 |
invoke con_write_asciiz, str_logged_in |
mov [ebp + thread_data.state], STATE_LOGIN |
.sendstr: |
sendFTP "331 Please specify the password" |
ret |
.login_fail: |
invoke con_write_asciiz, str_pass_err |
mov [ebp + thread_data.state], STATE_LOGIN_FAIL |
jmp .sendstr |
align 4 |
.2: |
sendFTP "530 Can't change to another user" |
ret |
/kernel/branches/net/applications/ftpd/ftpd.asm |
---|
0,0 → 1,455 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ftpd.asm - FTP Daemon for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
DEBUG = 0 ; if set to one, program will run in a single thread |
BUFFERSIZE = 8192 |
; using multiple's of 4 |
STATE_CONNECTED = 0*4 |
STATE_LOGIN = 1*4 |
STATE_LOGIN_FAIL = 2*4 ; When an invalid username was given |
STATE_ACTIVE = 3*4 |
TYPE_UNDEF = 0 |
TYPE_ASCII = 00000100b |
TYPE_EBDIC = 00001000b |
; subtypes for ascii & ebdic (np = default) |
TYPE_NP = 00000001b ; non printable |
TYPE_TELNET = 00000010b |
TYPE_ASA = 00000011b |
TYPE_IMAGE = 01000000b ; binary data |
TYPE_LOCAL = 10000000b ; bits per byte must be specified |
; lower 4 bits will hold this value |
MODE_NOTREADY = 0 |
MODE_ACTIVE = 1 |
MODE_PASSIVE_WAIT = 2 |
MODE_PASSIVE_OK = 3 |
MODE_PASSIVE_FAILED = 4 |
PERMISSION_EXEC = 1b ; LIST |
PERMISSION_READ = 10b |
PERMISSION_WRITE = 100b |
PERMISSION_DELETE = 1000b |
PERMISSION_CD = 10000b ; Change Directory |
ABORT = 1 shl 31 |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem+0x1000 ; required memory |
dd mem+0x1000 ; stack pointer |
dd params ; parameters |
dd path ; path |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../struct.inc' |
include '../libio.inc' |
include '../network.inc' |
macro sendFTP str { |
local string, length |
xor edi, edi |
mcall send, [ebp + thread_data.socketnum], string, length |
iglobal |
string db str, 13, 10 |
length = $ - string |
\} |
} |
include 'commands.inc' |
start: |
mcall 68, 11 ; init heap |
mcall 40, 1 shl 7 ; we only want network events |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; find path to main settings file (ftpd.ini) |
mov edi, path ; Calculate the length of zero-terminated string |
xor al, al |
mov ecx, 1024 |
repne scasb |
dec edi |
mov esi, str_ini ; append it with '.ini', 0 |
movsd |
movsb |
; now create the second path (users.ini) |
std |
mov al, '/' |
repne scasb |
lea ecx, [edi - path + 2] |
cld |
mov esi, path |
mov edi, path2 |
rep movsb |
mov esi, str_users |
movsd |
movsd |
movsw |
; initialize console |
invoke con_start, 1 |
invoke con_init, -1, -1, -1, -1, title |
; get settings from ini |
invoke ini.get_str, path, str_ftpd, str_ip, ini_buf, 16, 0 |
mov esi, ini_buf |
mov cl, '.' |
call ip_to_dword |
mov [serverip], ebx |
invoke ini.get_int, path, str_ftpd, str_port, 21 |
xchg al, ah |
mov [sockaddr1.port], ax |
xchg al, ah |
invoke con_printf, str1, eax |
add esp, 8 |
; open listening socket |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je sock_err |
mov [socketnum], eax |
invoke con_write_asciiz, str2 |
; mcall setsockopt, [socketnum], SOL_SOCKET, SO_REUSEADDR, &yes, |
; cmp eax, -1 |
; je opt_err |
mcall bind, [socketnum], sockaddr1, sockaddr1.length |
cmp eax, -1 |
je bind_err |
invoke con_write_asciiz, str2 |
invoke ini.get_int, path, str_ftpd, str_conn, 1 ; Backlog (max connections) |
mov edx, eax |
invoke con_write_asciiz, str2 |
mcall listen, [socketnum] |
cmp eax, -1 |
je listen_err |
invoke con_write_asciiz, str2b |
invoke ini.get_int, path, str_pasv, str_start, 2000 |
mov [pasv_start], ax |
invoke ini.get_int, path, str_pasv, str_end, 5000 |
mov [pasv_end], ax |
mov [alive], 1 |
mainloop: |
mcall 23, 100 ; Wait here for incoming connections on the base socket (socketnum) |
; One second timeout, we will use this to check if console is still working |
test eax, eax ; network event? |
jz .checkconsole |
if DEBUG |
jmp threadstart |
else |
mcall 51, 1, threadstart, 0 ; Start a new thread for every incoming connection |
; NOTE: upon initialisation of the thread, stack will not be available! |
end if |
jmp mainloop |
.checkconsole: |
invoke con_get_flags ; Is console still running? |
test eax, 0x0200 |
jz mainloop |
mcall close, [socketnum] ; kill the listening socket |
mov [alive], 0 |
mcall -1 ; and exit |
diff16 "threadstart", 0, $ |
threadstart: |
;;; mcall 68, 11 ; init heap |
mcall 68, 12, sizeof.thread_data ; allocate the thread data struct |
test eax, eax |
je exit |
lea esp, [eax + thread_data.stack] ; init stack |
mov ebp, eax |
mcall 40, 1 shl 7 ; we only want network events for this thread |
lea ebx, [ebp + thread_data.buffer] ; get information about the current process |
or ecx, -1 |
mcall 9 |
mov eax, dword [ebp + thread_data.buffer + 30] ; PID is at offset 30 |
mov [ebp + thread_data.pid], eax |
invoke con_set_flags, 0x03 |
invoke con_printf, str8, [ebp + thread_data.pid] ; print on the console that we have created the new thread successfully |
add esp, 8 ; balance stack |
invoke con_set_flags, 0x07 |
mcall accept, [socketnum], sockaddr1, sockaddr1.length ; time to accept the awaiting connection.. |
cmp eax, -1 |
je thread_exit |
mov [ebp + thread_data.socketnum], eax |
if DEBUG |
mcall close, [socketnum] ; close the listening socket |
end if |
mov [ebp + thread_data.state], STATE_CONNECTED |
mov [ebp + thread_data.permissions], 0 |
mov [ebp + thread_data.mode], MODE_NOTREADY |
lea eax, [ebp + thread_data.buffer] |
mov [ebp + thread_data.buffer_ptr], eax |
mov [ebp + thread_data.passivesocknum], -1 |
sendFTP "220 Welcome to KolibriOS FTP daemon" |
diff16 "threadloop", 0, $ |
threadloop: |
; Check if our socket is still connected |
mcall send, [ebp + thread_data.socketnum], 0, 0 ; Try to send zero bytes, if socket is closed, this will return -1 |
cmp eax, -1 |
je thread_exit |
cmp [alive], 0 ; Did main thread take a run for it? |
je thread_exit |
mcall 10 ; Wait for network event |
cmp [ebp + thread_data.mode], MODE_PASSIVE_WAIT |
jne .not_passive |
mov ecx, [ebp + thread_data.passivesocknum] |
lea edx, [ebp + thread_data.datasock] |
mov esi, sizeof.thread_data.datasock |
mcall accept |
cmp eax, -1 |
je .not_passive |
mov [ebp + thread_data.datasocketnum], eax |
mov [ebp + thread_data.mode], MODE_PASSIVE_OK |
mcall close ; [ebp + thread_data.passivesocknum] |
mov [ebp + thread_data.passivesocknum], -1 |
invoke con_write_asciiz, str_datasock |
.not_passive: |
mov ecx, [ebp + thread_data.socketnum] |
mov edx, [ebp + thread_data.buffer_ptr] |
mov esi, sizeof.thread_data.buffer ;;; FIXME |
mcall recv |
inc eax ; error? (-1) |
jz threadloop |
dec eax ; 0 bytes read? |
jz threadloop |
mov edi, [ebp + thread_data.buffer_ptr] |
add [ebp + thread_data.buffer_ptr], eax |
; Check if we received a newline character, if not, wait for more data |
mov ecx, eax |
mov al, 13 |
repne scasb |
jne threadloop |
; We got a command! |
mov byte [edi + 1], 0 ; append string with zero byte |
lea esi, [ebp + thread_data.buffer] |
mov ecx, [ebp + thread_data.buffer_ptr] |
sub ecx, esi |
mov [ebp + thread_data.buffer_ptr], esi ; reset buffer ptr |
invoke con_set_flags, 0x02 ; print received data to console (in green color) |
invoke con_write_asciiz, str_newline |
invoke con_write_asciiz, esi |
invoke con_set_flags, 0x07 |
push threadloop |
jmp parse_cmd |
listen_err: |
invoke con_set_flags, 0x0c ; print errors in red |
invoke con_write_asciiz, str3 |
jmp done |
bind_err: |
invoke con_set_flags, 0x0c ; print errors in red |
invoke con_write_asciiz, str4 |
jmp done |
sock_err: |
invoke con_set_flags, 0x0c ; print errors in red |
invoke con_write_asciiz, str6 |
jmp done |
done: |
invoke con_exit, 0 |
exit: |
mcall -1 |
thread_exit: |
invoke con_set_flags, 0x03 ; print thread info in blue |
invoke con_printf, str_bye, [ebp + thread_data.pid] ; print on the console that we are about to kill the thread |
add esp, 8 ; balance stack |
mcall 68, 13, ebp ; free the memory |
mcall -1 ; and kill the thread |
; initialized data |
title db 'KolibriOS FTP daemon 0.1', 0 |
str1 db 'Starting FTP daemon on port %u.', 0 |
str2 db '.', 0 |
str2b db ' OK!',10,0 |
str3 db 'Listen error',10,0 |
str4 db 10,'ERROR: local port is already in use.',10,0 |
;str5 db 'Setsockopt error.',10,10,0 |
str6 db 'ERROR: Could not open socket.',10,0 |
str7 db 'Got data!',10,10,0 |
str8 db 10,'Thread %d created',10,0 |
str_bye db 10,'Thread %d killed',10,0 |
str_logged_in db 'Login ok',10,0 |
str_pass_ok db 'Password ok',10,0 |
str_pass_err db 'Password/Username incorrect',10,0 |
str_pwd db 'Current directory is "%s"\n',0 |
str_err2 db 'ERROR: cannot open the directory.',10,0 |
str_datasock db 'Passive data socket connected.',10,0 |
str_notfound db 'ERROR: file not found.',10,0 |
str_sockerr db 'ERROR: socket error.',10,0 |
str_newline db 10, 0 |
str_mask db '*', 0 |
str_infinity db 0xff, 0xff, 0xff, 0xff, 0 |
months dd 'Jan ' |
dd 'Feb ' |
dd 'Mar ' |
dd 'Apr ' |
dd 'May ' |
dd 'Jun ' |
dd 'Jul ' |
dd 'Aug ' |
dd 'Sep ' |
dd 'Oct ' |
dd 'Nov ' |
dd 'Dec ' |
str_users db 'users' |
str_ini db '.ini', 0 |
str_port db 'port', 0 |
str_ftpd db 'ftpd', 0 |
str_conn db 'conn', 0 |
str_ip db 'ip', 0 |
str_pass db 'pass', 0 |
str_home db 'home', 0 |
str_mode db 'mode', 0 |
str_pasv db 'pasv', 0 |
str_start db 'start', 0 |
str_end db 'end', 0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0 |
.ip dd 0 |
rb 10 |
.length = $ - sockaddr1 |
; import |
align 4 |
@IMPORT: |
diff16 "import", 0, $ |
library console, 'console.obj',\ |
libini, 'libini.obj', \ |
libio, 'libio.obj' |
import console,\ |
con_start, 'START',\ |
con_init, 'con_init',\ |
con_write_asciiz, 'con_write_asciiz',\ |
con_exit, 'con_exit',\ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_printf, 'con_printf',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos',\ |
con_set_flags, 'con_set_flags',\ |
con_get_flags, 'con_get_flags' |
import libini,\ |
ini.get_str, 'ini_get_str',\ |
ini.get_int, 'ini_get_int' |
import libio,\ |
file.size, 'file_size',\ |
file.open, 'file_open',\ |
file.read, 'file_read',\ |
file.close, 'file_close',\ |
file.find.first, 'file_find_first',\ |
file.find.next, 'file_find_next',\ |
file.find.close, 'file_find_close' |
IncludeIGlobals |
i_end: |
diff16 "i_end", 0, $ |
; uninitialised data |
socketnum dd ? |
path rb 1024 |
path2 rb 1024 |
params rb 1024 |
serverip dd ? |
pasv_start dw ? |
pasv_end dw ? |
pasv_port dw ? |
ini_buf rb 3*4+3+1 |
alive db ? |
mem: |
/kernel/branches/net/applications/ftpd/users.ini |
---|
0,0 → 1,20 |
; Access modes |
; |
; List = 1 |
; Read = 2 |
; Write = 4 |
; Delete = 8 |
; Change directory = 16 |
[anonymous] |
; leavy pass empty to disable it |
pass= |
home=/rd/1/ |
mode=3 |
[test] |
pass=1234 |
home=/rd/1/ |
mode=31 |
/kernel/branches/net/applications/ftpd/ftpd.ini |
---|
0,0 → 1,8 |
[ftpd] |
port=21 |
conn=10 |
ip=127.0.0.1 |
[pasv] |
start=2000 |
end=5000 |
/kernel/branches/net/applications/libraries/network/network.asm |
---|
0,0 → 1,1295 |
format MS COFF |
public @EXPORT as 'EXPORTS' |
include '../../struct.inc' |
include '../../proc32.inc' |
include '../../macros.inc' |
purge section,mov,add,sub |
include '../../network.inc' |
section '.flat' code readable align 16 |
;;===========================================================================;; |
lib_init: ;//////////////////////////////////////////////////////////////////;; |
;;---------------------------------------------------------------------------;; |
;? Library entry point (called after library load) ;; |
;;---------------------------------------------------------------------------;; |
;> eax = pointer to memory allocation routine ;; |
;> ebx = pointer to memory freeing routine ;; |
;> ecx = pointer to memory reallocation routine ;; |
;> edx = pointer to library loading routine ;; |
;;---------------------------------------------------------------------------;; |
;< eax = 1 (fail) / 0 (ok) (library initialization result) ;; |
;;===========================================================================;; |
mov [mem.alloc], eax |
mov [mem.free], ebx |
mov [mem.realloc], ecx |
mov [dll.load], edx |
mov [DNSrequestID], 1 |
xor eax, eax |
ret |
;;===========================================================================;; |
;; in_addr_t __stdcall inet_addr(__in const char* hostname); ;; |
inet_addr: ;; |
;;---------------------------------------------------------------------------;; |
;? Convert the string from standard IPv4 dotted notation to integer IP addr. ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter = host name ;; |
;;---------------------------------------------------------------------------;; |
;< eax = IP address on success / -1 on error ;; |
;;===========================================================================;; |
; 0. Save used registers for __stdcall. |
push ebx esi edi |
mov esi, [esp+16] ; esi = hostname |
; 1. Check that only allowed symbols are present. |
; (hex digits, possibly letters 'x'/'X' and up to 3 dots) |
push esi |
xor ecx, ecx |
.calcdots_loop: |
; loop for all characters in string |
lodsb |
; check for end of string |
cmp al, 0 |
jz .calcdots_loop_done |
; check for dot |
cmp al, '.' |
jz .dot |
; check for digit |
sub al, '0' |
cmp al, 9 |
jbe .calcdots_loop |
; check for hex letter |
sub al, 'A' - '0' ; 'A'-'F' -> 0-5, 'a'-'f' -> 20h-25h |
and al, not 20h |
cmp al, 'F' - 'A' |
jbe .calcdots_loop |
; check for 'x'/'X' |
cmp al, 'X' - 'A' |
jz .calcdots_loop |
jmp .fail.pop |
.dot: |
inc ecx |
jmp .calcdots_loop |
.calcdots_loop_done: |
cmp ecx, 4 |
jae .fail.pop |
; 2. The name can be valid dotted name; try to convert, checking limit |
pop esi |
xor edi, edi ; edi = address |
push 0xFFFFFFFF |
pop edx ; edx = mask for rest of address |
; 2a. Convert name except for last group. |
jecxz .ip_convert_2b |
.ip_convert_2a: |
push ecx |
mov ecx, 0xFF ; limit for all groups except for last |
call .get_number |
pop ecx |
jc .fail |
cmp byte [esi-1], '.' |
jnz .fail |
shl edi, 8 |
shr edx, 8 |
add edi, eax |
loop .ip_convert_2a |
; 2b. Convert last group. |
.ip_convert_2b: |
mov ecx, edx |
call .get_number |
jc .fail |
cmp byte [esi-1], 0 |
jnz .fail |
@@: |
shl edi, 8 |
shr edx, 8 |
jnz @b |
add edi, eax |
; 2c. Convert to network byte order. |
bswap edi |
; 3. Set return value, restore used registers and return. |
xchg eax, edi |
.ret: |
pop edi esi ebx |
ret 4 |
; 4. On error, return -1. |
.fail.pop: |
pop esi |
.fail: |
push -1 |
pop eax |
jmp .ret |
;;===========================================================================;; |
;; Internal auxiliary function for IP parsing. ;; |
.get_number: ;; |
;;---------------------------------------------------------------------------;; |
;? Converts string to number. ;; |
;;---------------------------------------------------------------------------;; |
;> esi -> string ;; |
;> ecx = limit for number ;; |
;;---------------------------------------------------------------------------;; |
;< eax = number ;; |
;< CF set on error (too big number) / cleared on success ;; |
;< esi -> end of number representation ;; |
;;===========================================================================;; |
; 0. Save edx, which is used in caller. |
push edx |
; 1. Initialize number, zero eax so that lodsb gets full dword. |
xor eax, eax |
xor edx, edx |
; 2. Get used numeral system: 0x = hex, otherwise 0 = octal, otherwise decimal |
push 10 |
pop ebx |
lodsb |
cmp al, '0' |
jnz .convert |
push 8 |
pop ebx |
lodsb |
cmp al, 'x' |
jnz .convert |
add ebx, ebx |
; 3. Loop while digits are encountered. |
.convert: |
; 4. Convert digit from text representation to binary value. |
or al, 20h ; '0'-'9' -> '0'-'9', 'A'-'F' -> 'a'-'f' |
sub al, '0' |
cmp al, 9 |
jbe .digit |
sub al, 'a' - '0' |
cmp al, 'f' - 'a' |
ja .convert_done |
add al, 10 |
.digit: |
; 5. Digit must be less than base of numeral system. |
cmp eax, ebx |
jae .convert_done |
; 6. Advance the number. |
imul edx, ebx |
add edx, eax |
cmp edx, ecx |
ja .gn_error |
; 3b. Continue loop. |
lodsb |
jmp .convert |
.convert_done: |
; 7. Invalid character, number converted, return success. |
xchg eax, edx |
pop edx |
clc |
ret |
.gn_error: |
; 8. Too big number, return error. |
pop edx |
stc |
ret |
;;===========================================================================;; |
;; char* __stdcall inet_ntoa(struct in_addr in); ;; |
inet_ntoa: ;; |
;;---------------------------------------------------------------------------;; |
;? Convert the Internet host address to standard IPv4 dotted notation. ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter = host address ;; |
;;---------------------------------------------------------------------------;; |
;< eax = pointer to resulting string (in static buffer) ;; |
;;===========================================================================;; |
; 0. Save used registers for __stdcall. |
push ebx esi edi |
mov bl, 0xCD ; constant for div 10 |
; 1. Write octet 4 times. |
mov edi, .buffer |
mov edx, [esp+16] ; eax = in |
mov al, dl |
call .write |
mov al, dh |
shr edx, 16 |
call .write |
mov al, dl |
call .write |
mov al, dh |
call .write |
; 2. Replace final dot with terminating zero. |
mov byte [edi-1], 0 |
; 3. Restore used registers, set result value and return. |
pop edi esi ebx |
mov eax, .buffer |
ret 4 |
.write: |
movzx esi, al |
mul bl |
add esi, ('.' shl 8) + '0' |
shr ah, 3 ; ah = al / 10 |
movzx ecx, ah |
add ecx, ecx |
lea ecx, [ecx*5] |
sub esi, ecx ; lobyte(esi) = al % 10, hibyte(esi) = '.' |
test ah, ah |
jz .1digit |
cmp ah, 10 |
jb .2digit |
cmp ah, 20 |
sbb cl, cl |
add cl, '2' |
mov byte [edi], cl |
movzx ecx, cl |
lea ecx, [ecx*5] |
sub ah, cl |
sub ah, cl |
add ah, ('0'*11) and 255 |
mov byte [edi+1], ah |
mov word [edi+2], si |
add edi, 4 |
ret |
.2digit: |
add ah, '0' |
mov byte [edi], ah |
mov word [edi+1], si |
add edi, 3 |
ret |
.1digit: |
mov word [edi], si |
add edi, 2 |
ret |
struct __gai_reqdata |
socketnum dd ? |
; external code should not look on rest of this structure, |
; it is internal for getaddrinfo_start/process/abort |
reqid dw ? ; DNS request ID |
socktype db ? ; SOCK_* or 0 for any |
db ? |
service dd ? |
flags dd ? |
reserved rb 16 |
ends |
;;===========================================================================;; |
;; int __stdcall getaddrinfo(__in const char* hostname, ;; |
;; __in const char* servname, ;; |
;; __in const struct addrinfo* hints, ;; |
;; __out struct addrinfo **res); ;; |
getaddrinfo: ;; |
;;---------------------------------------------------------------------------;; |
;? Get a list of IP addresses and port numbers for given host and service ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter (optional) = host name ;; |
;> second parameter (optional) = service name (decimal number for now) ;; |
;> third parameter (optional) = hints for socketnum type ;; |
;> fourth parameter = pointer to result (head of L1-list) ;; |
;;---------------------------------------------------------------------------;; |
;< eax = 0 on success / one of EAI_ codes on error ;; |
;;===========================================================================;; |
; 0. Save used registers for __stdcall. |
push ebx esi edi |
mov edi, [esp+28] ; edi = res |
; 1. Create and send DNS packet. |
sub esp, sizeof.__gai_reqdata ; reserve stack place (1) |
push esp ; fifth parameter = pointer to (1) |
push edi ; fourth parameter = res |
push dword [esp+32+sizeof.__gai_reqdata] ; third parameter = hints |
push dword [esp+32+sizeof.__gai_reqdata] ; second parameter = servname |
push dword [esp+32+sizeof.__gai_reqdata] ; first parameter = hostname |
call getaddrinfo_start |
test eax, eax |
jns .ret ; if name resolved without network activity, return |
; 2. Wait for DNS reply. |
; 2a. Ignore all events except network stack. |
mcall 40, EVM_STACK |
push eax ; save previous event mask (2) |
; 2b. Get upper limit for wait time. Use timeout = 5 seconds. |
mcall 26, 9 ; get time stamp |
xchg esi, eax ; save time stamp to esi |
mov ebx, 500 ; start value for timeout |
add esi, ebx |
.wait: |
; 2c. Wait for event with timeout. |
mcall 23 ; wait for event - must be stack event |
; 2d. Check for timeout. |
test eax, eax |
lea eax, [esp+4] ; pointer to (1) |
jz .timeout |
; 3. Got packet. Call processing function. |
push edi ; second parameter: pointer to result |
push eax ; first parameter: pointer to reqdata |
call getaddrinfo_process |
; 4. Test whether wait loop must be continued. |
test eax, eax |
jns .ret.restore |
; 2e. Recalculate timeout value. |
mcall 26, 9 |
mov ebx, esi |
sub ebx, eax |
; 2f. Check that time is not over; if not, continue wait loop |
cmp ebx, 500 |
jbe .wait |
.timeout: |
; 5. Timeout: abort and return error |
push eax |
call getaddrinfo_abort |
and dword [edi], 0 |
push EAI_AGAIN |
pop eax |
.ret.restore: |
; 6. Restore event mask. |
pop ebx ; get event mask (2) |
push eax ; save return code (3) |
mcall 40 |
pop eax ; restore return code (3) |
.ret: |
; 7. Restore stack pointer, used registers and return. |
add esp, sizeof.__gai_reqdata ; undo (1) |
pop edi esi ebx |
ret 16 |
;;===========================================================================;; |
;; int __stdcall getaddrinfo_start(__in const char* hostname, ;; |
;; __in const char* servname, ;; |
;; __in const struct addrinfo* hints, ;; |
;; __out struct addrinfo **res, ;; |
;; __out struct __gai_reqdata* reqdata); ;; |
getaddrinfo_start: ;; |
;;---------------------------------------------------------------------------;; |
;? Initiator for getaddrinfo, sends DNS request ;; |
;;---------------------------------------------------------------------------;; |
;> first 4 parameters same as for getaddrinfo ;; |
;> last parameter = pointer to buffer for __gai_reqdata, must be passed to ;; |
;> getaddrinfo_process as is ;; |
;;---------------------------------------------------------------------------;; |
;< eax = <0 if wait loop must be entered / 0 on success / EAI_* on error ;; |
;;===========================================================================;; |
;; Known limitations: ;; |
;; 1. No support for TCP connections => ;; |
;; 1a. Long replies will be truncated, and not all IP addresses will be got. ;; |
;; 2. No support for iterative resolving => ;; |
;; 2a. In theory may fail with some servers. ;; |
;; 3. Assumes that domain for relative names is always root, ".". ;; |
;; 4. Does not support lookup of services by name, ;; |
;; only decimal representation is supported. ;; |
;; 5. Assumes that IPv4 is always configured, so AI_ADDRCONFIG has no effect.;; |
;;===========================================================================;; |
; 0. Create stack frame and save used registers for __stdcall. |
push ebx esi edi |
push ebp |
mov ebp, esp |
virtual at ebp-8 |
.recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
.recent_page dd ? ; this is for memory alloc in ._.generate_data |
rd 5 ; saved regs and return address |
.hostname dd ? |
.servname dd ? |
.hints dd ? |
.res dd ? |
.reqdata dd ? |
end virtual |
xor edi, edi |
push edi ; init .recent_page |
push edi ; init .recent_restsize |
; 1. Check that parameters are correct and can be handled by this implementation. |
; 1a. If 'res' pointer is given, set result to zero. |
mov eax, [.res] |
test eax, eax |
jz @f |
mov [eax], edi |
@@: |
; 1b. Only AI_SUPPORTED flags are supported for hints->ai_flags. |
mov ecx, [.hints] |
xor edx, edx |
jecxz .nohints |
mov edx, [ecx+addrinfo.ai_flags] |
.nohints: |
mov ebx, [.reqdata] |
mov [ebx+__gai_reqdata.flags], edx |
push EAI_BADFLAGS |
pop eax |
test edx, not AI_SUPPORTED |
jnz .ret |
; 1c. Either hostname or servname must be given. If AI_CANONNAME is set, |
; hostname must also be set. |
cmp [.hostname], edi |
jnz @f |
test dl, AI_CANONNAME |
jnz .ret |
push EAI_NONAME |
pop eax |
cmp [.servname], edi |
jz .ret |
@@: |
; 1d. Only IPv4 is supported, so hints->ai_family must be either PF_UNSPEC or PF_INET. |
push EAI_FAMILY |
pop eax |
jecxz @f |
cmp [ecx+addrinfo.ai_family], edi |
jz @f |
cmp [ecx+addrinfo.ai_family], AF_INET4 |
jnz .ret |
@@: |
; 1e. Valid combinations for ai_socktype/ai_protocol: 0/0 for any or |
; SOCK_STREAM/IPPROTO_TCP, SOCK_DGRAM/IPPROTO_UDP |
; (raw socketnums are not yet supported by the kernel) |
xor edx, edx ; assume 0=any if no hints |
jecxz .socketnum_type_ok |
mov edx, [ecx+addrinfo.ai_socktype] |
mov esi, [ecx+addrinfo.ai_protocol] |
; 1f. Test for ai_socktype=0 and ai_protocol=0. |
test edx, edx |
jnz .check_socktype |
test esi, esi |
jz .socketnum_type_ok |
; 1g. ai_socktype=0, ai_protocol is nonzero. |
push EAI_SERVICE |
pop eax |
inc edx ; edx = SOCK_STREAM |
cmp esi, IPPROTO_TCP |
jz .socketnum_type_ok |
inc edx ; edx = SOCK_DGRAM |
cmp esi, IPPROTO_UDP |
jz .socketnum_type_ok |
.ret: |
; Restore saved registers, destroy stack frame and return. |
mov esp, ebp |
pop ebp |
pop edi esi ebx |
ret 20 |
; 1h. ai_socktype is nonzero. |
.check_socktype: |
push EAI_SOCKTYPE |
pop eax |
cmp edx, SOCK_STREAM |
jz .check_tcp |
cmp edx, SOCK_DGRAM |
jnz .ret |
test esi, esi |
jz .socketnum_type_ok |
cmp esi, IPPROTO_UDP |
jz .socketnum_type_ok |
jmp .ret |
.check_tcp: |
test esi, esi |
jz .socketnum_type_ok |
cmp esi, IPPROTO_TCP |
jnz .ret |
.socketnum_type_ok: |
mov [ebx+__gai_reqdata.socktype], dl |
; 2. Resolve service. |
; 2a. If no name is given, remember value -1. |
push -1 |
pop edx |
mov esi, [.servname] |
test esi, esi |
jz .service_resolved |
; 2b. Loop for characters of string while digits are encountered. |
xor edx, edx |
xor eax, eax |
.serv_to_number: |
lodsb |
sub al, '0' |
cmp al, 9 |
ja .serv_to_number_done |
; for each digit, set edx = edx*10 + <digit> |
lea edx, [edx*5] |
lea edx, [edx*2+eax] |
; check for correctness: service port must fit in word |
cmp edx, 0x10000 |
jae .service_not_number |
jmp .serv_to_number |
.serv_to_number_done: |
and edx, 0xFFFF ; make sure that port fits |
; 2c. If zero character reached, name is resolved; |
; otherwise, return error (no support for symbolic names yet) |
cmp al, -'0' |
jz .service_resolved |
.service_not_number: |
push EAI_NONAME |
pop eax |
jmp .ret |
.service_resolved: |
; 2d. Save result to reqdata. |
mov [ebx+__gai_reqdata.service], edx |
; 3. Process host name. |
mov esi, [.hostname] |
; 3a. If hostname is not given, |
; use localhost for active socketnums and INADDR_ANY for passive socketnums. |
mov eax, 0x0100007F ; 127.0.0.1 in network byte order |
test byte [ebx+__gai_reqdata.flags], AI_PASSIVE |
jz @f |
xor eax, eax |
@@: |
test esi, esi |
jz .hostname_is_ip |
; 3b. Check for dotted IPv4 name. |
push esi |
call inet_addr |
cmp eax, -1 |
jz .resolve_hostname |
.hostname_is_ip: |
; 3c. hostname is valid representation of IP address, and we have resolved it. |
; Generate result, if .res pointer is not NULL. |
mov ebx, [.reqdata] |
mov esi, [.res] |
test esi, esi |
jz .no_result |
call getaddrinfo._.generate_data |
; 3d. Check for memory allocation error. |
.3d: |
push EAI_MEMORY |
pop eax |
test esi, esi |
jz .ret |
; 3e. If AI_CANONNAME is set, copy input name. |
test byte [ebx+__gai_reqdata.flags], AI_CANONNAME |
jz .no_result |
; 3f. Calculate length of name. |
push -1 |
pop ecx |
mov edi, [.hostname] |
xor eax, eax |
repnz scasb |
not ecx |
; 3g. Check whether it fits on one page with main data. |
cmp ecx, [.recent_restsize] |
jbe .name_fits |
; 3h. If not, allocate new page. |
push ecx |
add ecx, 4 ; first dword contains number of objects on the page |
mcall 68, 12 |
pop ecx |
; 3i. If allocation has failed, free addrinfo and return error. |
test eax, eax |
jnz .name_allocated |
push [.res] |
call freeaddrinfo |
push EAI_MEMORY |
pop eax |
jmp .ret |
.name_allocated: |
; 3j. Otherwise, set edi to allocated memory and continue to 3l. |
xchg edi, eax ; put result to edi |
push 1 |
pop eax |
stosd ; number of objects on the page = 1 |
jmp .copy_name |
.name_fits: |
; 3k. Get pointer to free memory in allocated page. |
mov edi, [.recent_page] |
mov eax, edi |
and eax, not 0xFFF |
inc dword [eax] ; increase number of objects |
.copy_name: |
; 3l. Put pointer to struct addrinfo. |
mov eax, [.res] |
mov eax, [eax] |
mov [eax+addrinfo.ai_canonname], edi |
; 3m. Copy name. |
rep movsb |
.no_result: |
; 3n. Return success. |
xor eax, eax |
jmp .ret |
; 4. Host address is not dotted IP. Test whether we are allowed to contact DNS. |
; Return error if no. |
.resolve_hostname: |
push EAI_NONAME |
pop eax |
mov ebx, [.reqdata] |
test byte [ebx+__gai_reqdata.flags], AI_NUMERICHOST |
jnz .ret |
; Host address is domain name. Contact DNS server. |
mov esi, [.hostname] |
; 5. Reserve stack place for UDP packet. |
; According to RFC1035, maximum UDP packet size in DNS is 512 bytes. |
sub esp, 512 |
; 6. Create DNS request packet. |
; 6a. Set pointer to start of buffer. |
mov edi, esp |
; 6b. Get request ID, write it to buffer. |
push 1 |
pop eax |
lock xadd [DNSrequestID], eax ; atomically increment ID, get old value |
stosw |
mov [ebx+__gai_reqdata.reqid], ax |
; 6c. Packed field: QR=0 (query), Opcode=0000 (standard query), |
; AA=0 (ignored in requests), TC=0 (no truncation), |
; RD=1 (recursion desired) |
mov al, 00000001b |
stosb |
; 6d. Packed field: ignored in requests |
mov al, 0 |
stosb |
; 6e. Write questions count = 1 and answers count = 0 |
; Note that network byte order is big-endian. |
mov eax, 0x00000100 |
stosd |
; 6f. Write nameservers count = 0 and additional records count = 0 |
xor eax, eax |
stosd |
; 6g. Write request data: name |
; According to RFC1035, maximum length of name is 255 bytes. |
; For correct names, buffer cannot overflow. |
lea ebx, [esi+256] ; ebx = limit for name (including terminating zero) |
; translate string "www.yandex.ru" {00} to byte data {03} "www" {06} "yandex" {02} "ru" {00} |
.nameloop: ; here we go in the start of each label: before "www", before "yandex", before "ru" |
xor ecx, ecx ; ecx = length of current label |
inc edi ; skip length, it will be filled later |
.labelloop: ; here we go for each symbol of name |
lodsb ; get next character |
test al, al ; terminating zero? |
jz .endname |
cmp esi, ebx ; limit exceeded? |
jae .wrongname |
cmp al, '.' ; end of label? |
jz .labelend |
stosb ; put next character |
inc ecx ; increment label length |
jmp .labelloop |
.wrongname: |
push EAI_NONAME |
pop eax |
jmp .ret |
.labelend: |
test ecx, ecx ; null label can be only in the end of name |
jz .wrongname |
.endname: |
cmp ecx, 63 |
ja .wrongname |
; write length to byte [edi-ecx-1] |
mov eax, ecx |
neg eax |
mov byte [edi+eax-1], cl |
cmp byte [esi-1], 0 ; that was last label in the name? |
jnz .nameloop |
; write terminating zero if not yet |
mov al, 0 |
cmp byte [edi-1], al |
jz @f |
stosb |
@@: |
; 6h. Write request data: |
; query type = A (host address) = 1, |
; query class = IN (internet IPv4 address) = 1 |
; Note that network byte order is big-endian. |
mov eax, 0x01000100 |
stosd |
; 7. Get DNS server address. |
mcall 76, API_IPv4 + 4 ; protocol IP=0, device number=0, function=get DNS address |
cmp eax, -1 |
je .ret.dnserr |
mov esi, eax ; put server address to esi |
; 8. Open UDP socketnum to DNS server, port 53. |
; 8a. Create new socketnum. |
mcall 75, 0, AF_INET4, SOCK_DGRAM |
cmp eax, -1 ; error? |
jz .ret.dnserr |
mov ecx, eax ; put socketnum handle to ecx |
; 8b. Create sockaddr structure on the stack. |
push 0 |
push 0 ; sin_zero |
push esi ; sin_addr |
push AF_INET4 + (53 shl 24) |
; sin_family and sin_port in network byte order |
; 8c. Connect. |
mcall 75, 4, , esp, sizeof.sockaddr_in |
; 8d. Restore the stack, undo 8b. |
add esp, esi |
; 8e. Check result. |
cmp eax, -1 |
jz .ret.close |
; 9. Send DNS request packet. |
sub edi, esp ; get packet length |
mov esi, edi |
xor edi, edi |
mcall 75, 6, , esp |
cmp eax, -1 |
jz .ret.close |
mov eax, [.reqdata] |
mov [eax+__gai_reqdata.socketnum], ecx |
push -1 |
pop eax ; return status: more processing required |
jmp .ret.dns |
.ret.close: |
mcall 75, 1 |
.ret.dnserr: |
push EAI_AGAIN |
pop eax |
.ret.dns: |
; 6. Restore stack pointer and return. |
jmp .ret |
;;===========================================================================;; |
;; int __stdcall getaddrinfo_process(__in struct __gai_reqdata* reqdata, ;; |
;; __out struct addrinfo** res); ;; |
getaddrinfo_process: ;; |
;;---------------------------------------------------------------------------;; |
;? Processes network events from DNS reply ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
;> second parameter = same as for getaddrinfo ;; |
;;---------------------------------------------------------------------------;; |
;< eax = -1 if more processing required / 0 on success / >0 = error code ;; |
;;===========================================================================;; |
; 0. Create stack frame. |
push ebp |
mov ebp, esp |
virtual at ebp-.locals_size |
.locals_start: |
.datagram rb 512 |
.addrname dd ? |
.name dd ? |
.res_list_tail dd ? |
.cname dd ? |
.recent_restsize dd ? ; this is for memory alloc in ._.generate_data |
.recent_page dd ? ; this is for memory alloc in ._.generate_data |
.locals_size = $ - .locals_start |
rd 2 |
.reqdata dd ? |
.res dd ? |
end virtual |
xor eax, eax |
push eax ; initialize .recent_page |
push eax ; initialize .recent_restsize |
push eax ; initialize .cname |
push [.res] ; initialize .res_list_tail |
sub esp, .locals_size-16 ; reserve place for other vars |
mov edx, esp ; edx -> buffer for datagram |
; 1. Save used registers for __stdcall. |
push ebx esi edi |
mov edi, [.reqdata] |
; 2. Read UDP datagram. |
mov ecx, [edi+__gai_reqdata.socketnum] |
push edi |
mcall 75, 7, , , 512, 0 |
pop edi |
; 3. Ignore events for other socketnums (return if no data read) |
test eax, eax |
jz .ret.more_processing_required |
; 4. Sanity check: discard too short packets. |
xchg ecx, eax ; save packet length in ecx |
cmp ecx, 12 |
jb .ret.more_processing_required |
; 5. Discard packets with ID != request ID. |
mov eax, dword [edi+__gai_reqdata.reqid] |
cmp ax, [edx] |
jnz .ret.more_processing_required |
; 6. Sanity check: discard query packets. |
test byte [edx+2], 80h |
jz .ret.more_processing_required |
; 7. Sanity check: must be exactly one query (our). |
cmp word [edx+4], 0x0100 ; note network byte order |
jnz .ret.more_processing_required |
; 8. Check for errors. Return EAI_NONAME for error code 3 and EAI_FAIL for other. |
mov al, [edx+3] |
and al, 0xF |
jz @f |
cmp al, 3 |
jnz .ret.no_recovery |
jmp .ret.no_name |
@@: |
; 9. Locate answers section. Exactly 1 query is present in this packet. |
add ecx, edx ; ecx = limit |
lea esi, [edx+12] |
call .skip_name |
lodsd ; skip QTYPE and QCLASS field |
cmp esi, ecx |
ja .ret.no_recovery |
; 10. Loop through all answers. |
movzx ebx, word [edx+6] ; get answers count |
xchg bl, bh ; network -> Intel byte order |
.answers_loop: |
dec ebx |
js .answers_done |
; 10a. Process each record. |
mov [.name], esi |
; 10b. Skip name field. |
call .skip_name |
; 10c. Get record information, handle two types for class IN (internet). |
lodsd ; get type and class |
cmp esi, ecx |
ja .ret.no_recovery |
cmp eax, 0x01000500 ; type=5, class=1? |
jz .got_cname |
cmp eax, 0x01000100 ; type=1, class=1? |
jnz .answers_loop.next |
.got_addr: |
; 10d. Process record A, host address. |
add esi, 10 |
cmp esi, ecx |
ja .ret.no_recovery |
cmp word [esi-6], 0x0400 ; RDATA for A records must be 4 bytes long |
jnz .ret.no_recovery |
mov eax, [.name] |
mov [.addrname], eax |
; 10e. Create corresponding record in the answer. |
push ebx ecx esi |
mov eax, [esi-4] ; IP address |
mov esi, [.res_list_tail] ; pointer to result |
test esi, esi |
jz .no_result ; do not save if .res is NULL |
mov ebx, [.reqdata] ; request data |
call getaddrinfo._.generate_data |
mov [.res_list_tail], esi |
pop esi ecx ebx |
cmp [.res_list_tail], 0 |
jnz .answers_loop |
; 10f. If generate_data failed (this means memory allocation failure), abort |
jmp .ret.no_memory |
.no_result: |
pop esi ecx ebx |
jmp .answers_loop |
.got_cname: |
; 10g. Process record CNAME, main host name. |
lea eax, [esi+6] |
mov [.cname], eax |
.answers_loop.next: |
; 10h. Skip other record fields, advance to next record. |
lodsd ; skip TTL |
xor eax, eax |
lodsw ; get length of RDATA field |
xchg al, ah ; network -> Intel byte order |
add esi, eax |
cmp esi, ecx |
ja .ret.no_recovery |
jmp .answers_loop |
.answers_done: |
; 11. Check that there is at least 1 answer. |
mov eax, [.res_list_tail] |
cmp [.res], eax |
jz .ret.no_data |
; 12. If canonical name was required, add it now. |
mov eax, [.reqdata] |
test byte [eax+__gai_reqdata.flags], AI_CANONNAME |
jz .no_canon_name |
; 12a. If at least one CNAME record is present, use name from last such record. |
; Otherwise, use name from one of A records. |
mov esi, [.cname] |
test esi, esi |
jnz .has_cname |
mov esi, [.addrname] |
.has_cname: |
; 12b. Calculate name length. |
call .get_name_length |
jc .ret.no_recovery |
; 12c. Check that the caller really want to get data. |
cmp [.res], 0 |
jz .no_canon_name |
; 12d. Allocate memory for name. |
call getaddrinfo._.memalloc |
test edi, edi |
jz .ret.no_memory |
; 12e. Make first entry in .res list point to canonical name. |
mov eax, [.res] |
mov eax, [eax] |
mov [eax+addrinfo.ai_canonname], edi |
; 12f. Decode name. |
call .decode_name |
.no_canon_name: |
; 13. Set status to success. |
xor eax, eax |
jmp .ret.close |
; Handle errors. |
.ret.more_processing_required: |
push -1 |
pop eax |
jmp .ret |
.ret.no_recovery: |
push EAI_FAIL |
pop eax |
jmp .ret.destroy |
.ret.no_memory: |
push EAI_MEMORY |
pop eax |
jmp .ret.destroy |
.ret.no_name: |
.ret.no_data: |
push EAI_NONAME |
pop eax |
.ret.destroy: |
; 14. If an error occured, free memory acquired so far. |
push eax |
mov esi, [.res] |
test esi, esi |
jz @f |
pushd [esi] |
call freeaddrinfo |
and dword [esi], 0 |
@@: |
pop eax |
.ret.close: |
; 15. Close socketnum. |
push eax |
mov ecx, [.reqdata] |
mov ecx, [ecx+__gai_reqdata.socketnum] |
mcall 75, 1 |
pop eax |
; 16. Restore used registers, destroy stack frame and return. |
.ret: |
pop edi esi ebx |
mov esp, ebp |
pop ebp |
ret 8 |
;;===========================================================================;; |
;; Internal auxiliary function for skipping names in DNS packet. ;; |
.skip_name: ;; |
;;---------------------------------------------------------------------------;; |
;? Skips name in DNS packet. ;; |
;;---------------------------------------------------------------------------;; |
;> esi -> name ;; |
;> ecx = end of packet ;; |
;;---------------------------------------------------------------------------;; |
;< esi -> end of name ;; |
;;===========================================================================;; |
xor eax, eax |
cmp esi, ecx |
jae .skip_name.done |
lodsb |
test al, al |
jz .skip_name.done |
test al, 0xC0 |
jnz .skip_name.pointer |
add esi, eax |
jmp .skip_name |
.skip_name.pointer: |
inc esi |
.skip_name.done: |
ret |
;;===========================================================================;; |
;; Internal auxiliary function for calculating length of name in DNS packet. ;; |
.get_name_length: ;; |
;;---------------------------------------------------------------------------;; |
;? Calculate length of name (including terminating zero) in DNS packet. ;; |
;;---------------------------------------------------------------------------;; |
;> edx = start of packet ;; |
;> esi -> name ;; |
;> ecx = end of packet ;; |
;;---------------------------------------------------------------------------;; |
;< eax = length of name ;; |
;< CF set on error / cleared on success ;; |
;;===========================================================================;; |
xor ebx, ebx ; ebx will hold data length |
.get_name_length.zero: |
xor eax, eax |
.get_name_length.loop: |
cmp esi, ecx |
jae .get_name_length.fail |
lodsb |
test al, al |
jz .get_name_length.done |
test al, 0xC0 |
jnz .get_name_length.pointer |
add esi, eax |
inc ebx |
add ebx, eax |
cmp ebx, 256 |
jbe .get_name_length.loop |
.get_name_length.fail: |
stc |
ret |
.get_name_length.pointer: |
and al, 0x3F |
mov ah, al |
lodsb |
lea esi, [edx+eax] |
jmp .get_name_length.zero |
.get_name_length.done: |
test ebx, ebx |
jz .get_name_length.fail |
xchg eax, ebx |
clc |
ret |
;;===========================================================================;; |
;; Internal auxiliary function for decoding DNS name. ;; |
.decode_name: ;; |
;;---------------------------------------------------------------------------;; |
;? Decode name in DNS packet. ;; |
;;---------------------------------------------------------------------------;; |
;> edx = start of packet ;; |
;> esi -> name in packet ;; |
;> edi -> buffer for decoded name ;; |
;;===========================================================================;; |
xor eax, eax |
lodsb |
test al, al |
jz .decode_name.done |
test al, 0xC0 |
jnz .decode_name.pointer |
mov ecx, eax |
rep movsb |
mov al, '.' |
stosb |
jmp .decode_name |
.decode_name.pointer: |
and al, 0x3F |
mov ah, al |
lodsb |
lea esi, [edx+eax] |
jmp .decode_name |
.decode_name.done: |
mov byte [edi-1], 0 |
ret |
;;===========================================================================;; |
;; Internal auxiliary function for allocating memory for getaddrinfo. ;; |
getaddrinfo._.memalloc: ;; |
;;---------------------------------------------------------------------------;; |
;? Memory allocation. ;; |
;;---------------------------------------------------------------------------;; |
;> eax = size in bytes, must be less than page size. ;; |
;> [ebp-4] = .recent_page = last allocated page ;; |
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
;;---------------------------------------------------------------------------;; |
;< edi -> allocated memory / NULL on error ;; |
;;===========================================================================;; |
; 1. Set edi to result of function. |
mov edi, [ebp-4] |
; 2. Check whether we need to allocate a new page. |
cmp eax, [ebp-8] |
jbe .no_new_page |
; 2. Allocate new page if need. Reset edi to new result. |
push eax ebx |
mcall 68, 12, 0x1000 |
xchg edi, eax ; put result to edi |
pop ebx eax |
; 3. Check returned value of allocator. Fail if it failed. |
test edi, edi |
jz .ret |
; 4. Update .recent_page and .recent_restsize. |
add edi, 4 |
sub ecx, 4 |
mov [ebp-4], edi |
mov [ebp-8], ecx |
.no_new_page: |
; 5. Increase number of objects on this page. |
push eax |
mov eax, edi |
and eax, not 0xFFF |
inc dword [eax] |
pop eax |
; 6. Advance last allocated pointer, decrease memory size. |
add [ebp-4], eax |
sub [ebp-8], eax |
; 7. Return. |
.ret: |
ret |
;;===========================================================================;; |
;; Internal auxiliary function for freeing memory for freeaddrinfo. ;; |
getaddrinfo._.memfree: ;; |
;;---------------------------------------------------------------------------;; |
;? Free memory. ;; |
;;---------------------------------------------------------------------------;; |
;> eax = pointer ;; |
;;===========================================================================;; |
; 1. Get start of page. |
mov ecx, eax |
and ecx, not 0xFFF |
; 2. Decrease number of objects. |
dec dword [ecx] |
; 3. If it goes to zero, free the page. |
jnz @f |
push ebx |
mcall 68, 13 |
pop ebx |
@@: |
; 4. Done. |
ret |
;;===========================================================================;; |
getaddrinfo._.generate_data: ;; |
;;---------------------------------------------------------------------------;; |
;? Generate item(s) of getaddrinfo result list by one IP address. ;; |
;;---------------------------------------------------------------------------;; |
;> eax = IP address ;; |
;> ebx = request data ;; |
;> esi = pointer to result ;; |
;> [ebp-4] = .recent_page = last allocated page ;; |
;> [ebp-8] = .recent_restsize = bytes rest in last allocated page ;; |
;;---------------------------------------------------------------------------;; |
;< esi = pointer to next list item for result / NULL on error ;; |
;;===========================================================================;; |
; 1. If no service is given, append one item with zero port. |
; append one item with zero socktype/protocol/port. |
cmp [ebx+__gai_reqdata.service], -1 |
jnz .has_service |
call .append_item |
; 1a. If neither protocol nor socktype were specified, |
; leave zeroes in socktype and protocol. |
mov cl, [ebx+__gai_reqdata.socktype] |
test cl, cl |
jz .no_socktype |
; 1b. Otherwise, set socktype and protocol to desired. |
call .set_socktype |
.no_socktype: |
ret |
.has_service: |
; 2. If TCP is allowed, append item for TCP. |
cmp [ebx+__gai_reqdata.socktype], 0 |
jz .tcp_ok |
cmp [ebx+__gai_reqdata.socktype], SOCK_STREAM |
jnz .tcp_disallowed |
.tcp_ok: |
call .append_item |
mov cl, SOCK_STREAM |
call .set_socktype |
call .set_port |
.tcp_disallowed: |
; 3. If UDP is allowed, append item for UDP. |
cmp [ebx+__gai_reqdata.socktype], 0 |
jz .udp_ok |
cmp [ebx+__gai_reqdata.socktype], SOCK_DGRAM |
jnz .udp_disallowed |
.udp_ok: |
call .append_item |
mov cl, SOCK_DGRAM |
call .set_socktype |
call .set_port |
.udp_disallowed: |
ret |
.append_item: |
; 1. Allocate memory for struct sockaddr_in and struct addrinfo. |
push eax |
push sizeof.addrinfo + sizeof.sockaddr_in |
pop eax |
call getaddrinfo._.memalloc |
; 2. Check for memory allocation fail. |
test edi, edi |
jz .no_memory |
; 3. Zero allocated memory. |
push (sizeof.addrinfo + sizeof.sockaddr_in) / 4 |
pop ecx |
xor eax, eax |
push edi |
rep stosd |
pop edi |
; 4. Fill struct addrinfo. |
mov eax, [ebx+__gai_reqdata.flags] |
mov [edi+addrinfo.ai_flags], eax |
mov byte [edi+addrinfo.ai_family], AF_INET4 |
mov byte [edi+addrinfo.ai_addrlen], sizeof.sockaddr_in |
lea ecx, [edi+sizeof.addrinfo] |
mov [edi+addrinfo.ai_addr], ecx |
; 5. Fill struct sockaddr_in. |
mov byte [ecx+sockaddr_in.sin_family], AF_INET4 |
pop eax |
mov [ecx+sockaddr_in.sin_addr], eax |
; 6. Append new item to the list. |
mov [esi], edi |
lea esi, [edi+addrinfo.ai_next] |
; 7. Return. |
ret |
.no_memory: |
pop eax |
xor esi, esi |
ret |
.set_socktype: |
; Set ai_socktype and ai_protocol fields by given socketnum type. |
mov byte [edi+addrinfo.ai_socktype], cl |
dec cl |
jnz .set_udp |
.set_tcp: |
mov byte [edi+addrinfo.ai_protocol], IPPROTO_TCP |
ret |
.set_udp: |
mov byte [edi+addrinfo.ai_protocol], IPPROTO_UDP |
ret |
.set_port: |
; Just copy port from input __gai_reqdata to output addrinfo. |
push edx |
mov edx, [ebx+__gai_reqdata.service] |
xchg dl, dh ; convert to network byte order ;;;;; CHECKME |
mov [edi+sizeof.addrinfo+sockaddr_in.sin_port], dx |
pop edx |
ret |
;;===========================================================================;; |
;; void __stdcall getaddrinfo_abort(__in struct __gai_reqdata* reqdata); ;; |
getaddrinfo_abort: ;; |
;;---------------------------------------------------------------------------;; |
;? Abort process started by getaddrinfo_start, free all resources. ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter = pointer to struct __gai_reqdata filled by ..._start ;; |
;;===========================================================================;; |
; 0. Save used registers for __stdcall. |
push ebx |
; 1. Allocated resources: only socketnum, so close it and return. |
mov eax, [esp+8] |
mov ecx, [eax+__gai_reqdata.socketnum] |
mcall 75, 1 |
; 2. Restore used registers and return. |
pop ebx |
ret 4 |
;;===========================================================================;; |
;; void __stdcall freeaddrinfo(__in struct addrinfo* ai); ;; |
freeaddrinfo: ;; |
;;---------------------------------------------------------------------------;; |
;? Free one or more addrinfo structures returned by getaddrinfo. ;; |
;;---------------------------------------------------------------------------;; |
;> first parameter = head of list of structures ;; |
; (may be arbitrary sublist of original) ;; |
;;===========================================================================;; |
; 1. Loop for all items in the list. |
mov edx, [esp+4] ; eax = ai |
.loop: |
test edx, edx |
jz .done |
; 2. Free each item. |
; 2a. Free ai_canonname, if allocated. |
mov eax, [edx+addrinfo.ai_canonname] |
test eax, eax |
jz .no_canon_name |
call getaddrinfo._.memfree |
.no_canon_name: |
; 2b. Remember next item |
; (after freeing the field ai_next can became unavailable). |
pushd [edx+addrinfo.ai_next] |
; 2c. Free item itself. |
xchg eax, edx |
call getaddrinfo._.memfree |
; 2d. Restore pointer to next item and continue loop. |
pop edx |
jmp .loop |
.done: |
; 3. Done. |
ret 4 |
;;===========================================================================;; |
;;///////////////////////////////////////////////////////////////////////////;; |
;;===========================================================================;; |
;! Exported functions section ;; |
;;===========================================================================;; |
;;///////////////////////////////////////////////////////////////////////////;; |
;;===========================================================================;; |
align 4 |
@EXPORT: |
export \ |
lib_init , 'lib_init' , \ |
0x00010001 , 'version' , \ |
inet_addr , 'inet_addr' , \ |
inet_ntoa , 'inet_ntoa' , \ |
getaddrinfo , 'getaddrinfo' , \ |
getaddrinfo_start , 'getaddrinfo_start' , \ |
getaddrinfo_process , 'getaddrinfo_process' , \ |
getaddrinfo_abort , 'getaddrinfo_abort' , \ |
freeaddrinfo , 'freeaddrinfo' |
section '.data' data readable writable align 16 |
; uninitialized data |
mem.alloc dd ? |
mem.free dd ? |
mem.realloc dd ? |
dll.load dd ? |
DNSrequestID dd ? |
inet_ntoa.buffer rb 16 ; static buffer for inet_ntoa |
/kernel/branches/net/applications/synergyc/synergyc.asm |
---|
0,0 → 1,384 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Synergyc.asm - Synergy client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem+0x1000 ; required memory |
dd mem+0x1000 ; stack pointer |
dd 0 ; parameters |
dd path ; path |
__DEBUG__ equ 1 ; enable/disable |
__DEBUG_LEVEL__ equ 1 ; 1 = all, 2 = errors |
BUFFERSIZE equ 1024 |
DEFAULTPORT equ 24800 |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../network.inc' |
start: |
cld |
mov edi, path ; Calculate the length of zero-terminated string |
xor al, al |
mov ecx, 1024 |
repne scasb |
dec edi |
mov esi, filename ; append the path with '.ini' |
movsd |
movsb |
mcall 68, 11 |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
push path |
call [con_write_asciiz] |
push newline |
call [con_write_asciiz] |
push newline |
call [con_write_asciiz] |
invoke ini.get_str, path, str_remote, str_ip, buffer_ptr, 16, 0 |
test eax, eax |
jnz error |
invoke ini.get_int, path, str_remote, str_port, DEFAULTPORT |
xchg al, ah |
mov [sockaddr1.port], ax |
push str1 |
call [con_write_asciiz] |
push buffer_ptr |
call [con_write_asciiz] |
push newline |
call [con_write_asciiz] |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je error |
mov [socketnum], eax |
push buffer_ptr ; hostname |
call [inet_addr] |
cmp eax, -1 |
je error |
mov [sockaddr1.ip], eax |
mcall connect, [socketnum], sockaddr1, 18 |
push str7 |
call [con_write_asciiz] |
mcall 40, 1 shl 7; + 7 |
login: |
call wait_for_data |
push buffer_ptr + 4 |
call [con_write_asciiz] |
cmp dword [buffer_ptr], 11 shl 24 |
jne login |
cmp dword [buffer_ptr + 4], 'Syne' |
jne login |
cmp word [buffer_ptr + 8], 'rg' |
jne login |
cmp byte [buffer_ptr + 10], 'y' |
jne login |
push str2 |
call [con_write_asciiz] |
lea edi, [buffer_ptr + 11 + 4 + 4] |
invoke ini.get_str, path, str_local, str_name, edi, 255, 0 |
xor al , al |
mov ecx, 256 |
repne scasb |
sub edi, buffer_ptr + 1 + 4 |
mov esi, edi |
bswap edi |
mov dword [buffer_ptr], edi |
mov edi, esi |
sub edi, 11 + 4 |
bswap edi |
mov dword [buffer_ptr + 11 + 4], edi |
add esi, 4 |
mcall send, [socketnum], buffer_ptr, , 0 |
mainloop: |
call wait_for_data |
mov edi, buffer_ptr |
.command: |
push eax edi |
cmp dword [edi + 4], 'QINF' ; query screen info |
je .qinf |
cmp dword [edi + 4], 'CALV' ; alive ? |
je .calv |
cmp dword [edi + 4], 'CINN' ; mouse moved into screen |
je .cinn |
cmp dword [edi + 4], 'DCLP' ; Clipboard event |
je .dclp |
cmp dword [edi + 4], 'DMMV' ; Mouse moved |
je .dmmv |
cmp dword [edi + 4], 'COUT' ; leave screen |
je .cout |
cmp dword [edi + 4], 'DMDN' ; mouse button down |
je .dmdn |
cmp dword [edi + 4], 'DMUP' ; mouse button released |
je .dmup |
cmp dword [edi + 4], 'CNOP' ; no operation |
je .next |
cmp dword [edi + 4], 'CIAK' ; resolution changed? |
je .ciak |
push str3 |
call [con_write_asciiz] |
mov byte[edi+8],0 |
add edi, 4 |
push edi |
call [con_write_asciiz] |
push newline |
call [con_write_asciiz] |
.next: |
pop edi eax |
mov ecx, dword [edi] |
bswap ecx |
add ecx, 4 |
sub eax, ecx |
jle mainloop |
add edi, ecx |
jmp .command |
.qinf: |
mcall 14 ; get screen info |
add eax, 0x00010001 |
bswap eax |
mov dword [screeninfo.size], eax |
mcall send, [socketnum], screeninfo, screeninfo.length, 0 ; send client name |
jmp .next |
.calv: |
mcall send, [socketnum], calv, calv.length, 0 ; looks like ping-pong event |
jmp .next |
.cinn: |
mov edx, [edi + 8] |
bswap edx |
mcall 18, 19, 4 |
; ignore sequence number and modify key mask for now |
push str6 |
call [con_write_asciiz] |
jmp .next |
.dclp: |
jmp .next |
.dmmv: |
mov edx, [edi + 8] |
bswap edx |
mcall 18, 19, 4 |
mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP |
push str4 |
call [con_write_asciiz] |
jmp .next |
.cout: |
jmp .next |
.dmdn: |
movzx eax, byte [edi + 8] |
or [mousestate], eax |
mcall 18, 19, 5, [mousestate] |
mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP |
push str5 |
call [con_write_asciiz] |
jmp .next |
.dmup: |
movzx eax, byte [edi + 8] |
not eax |
and [mousestate], eax |
mcall 18, 19, 5, [mousestate] |
mcall send, [socketnum], cnop, cnop.length, 0 ; reply with NOP |
push str5 |
call [con_write_asciiz] |
jmp .next |
.ciak: |
jmp .next |
error: |
push str_err |
call [con_write_asciiz] |
call [con_gets] |
push 1 |
call [con_exit] |
mcall close, [socketnum] |
exit: |
mcall -1 |
wait_for_data: |
mcall 10 ; wait for data |
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 |
cmp eax, -1 |
je wait_for_data |
cmp eax, 8 |
jl wait_for_data |
ret |
; data |
title db 'Synergy client',0 |
str1 db 'Connecting to: ',0 |
str7 db 'Connected!',13,10,0 |
str2 db 13,10,'Handshake received',13,10,0 |
str3 db 'Unsupported command: ',0 |
newline db 13,10,0 |
str4 db 'mouse moved',13,10,0 |
str5 db 'mouse buttons changed',13,10,0 |
str6 db 'Enter screen',13,10,0 |
str_err db 'Error occured !',13,10,'Press any key to quit',0 |
screeninfo: |
dd (screeninfo.length - 4) shl 24 |
db 'DINF' |
dw 0 ; coordinate of leftmost pixel |
dw 0 ; coordiante of topmost pixel |
.size: |
dw 0 ; width |
dw 0 ; height |
dw 0 ; size of warp zone |
dw 0xb88b ; x position of the mouse on the secondary screen (no idea what it means) |
dw 0xbcfb ; y position of the mouse on the secondary screen |
.length = $ - screeninfo |
calv: |
dd (4) shl 24 |
db 'CALV' |
.length = $ - calv + 8 ; also send cnop |
cnop: |
dd (4) shl 24 |
db 'CNOP' |
.length = $ - cnop |
mousestate dd 0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0 |
.ip dd 192 + 168 shl 8 + 1 shl 16 + 115 shl 24 |
rb 10 |
filename db '.ini', 0 |
str_local db 'local', 0 |
str_name db 'name', 0 |
str_remote db 'remote', 0 |
str_port db 'port', 0 |
str_ip db 'ip', 0 |
; import |
align 16 |
@IMPORT: |
library console, 'console.obj',\ |
network, 'network.obj',\ |
libini, 'libini.obj' |
import network,\ |
inet_addr, 'inet_addr' |
import console, \ |
con_start, 'START',\ |
con_init, 'con_init',\ |
con_write_asciiz, 'con_write_asciiz',\ |
con_exit, 'con_exit',\ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos' |
import libini,\ |
ini.get_str, 'ini_get_str',\ |
ini.get_int, 'ini_get_int' |
align 4 |
i_end: |
socketnum dd ? |
buffer_ptr rb BUFFERSIZE |
path rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/synergyc/synergyc.ini |
---|
0,0 → 1,6 |
[local] |
name = karaboeia |
[remote] |
ip = 192.168.1.115 |
port = 24800 |
/kernel/branches/net/applications/tcpserv/tcpserv.asm |
---|
0,0 → 1,168 |
format binary as "" |
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd 0 ; parameters |
dd 0 ; path |
BUFFERSIZE equ 1500 |
; useful includes |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../network.inc' |
; entry point |
start: |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
mcall 40, 1 shl 7 ; we only want network events |
push str1 |
call [con_write_asciiz] |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
je sock_err |
mov [socketnum], eax |
;; mcall setsockopt, [socketnum], SOL_SOCKET, SO_REUSEADDR, &yes, |
;; cmp eax, -1 |
;; je opt_err |
mcall bind, [socketnum], sockaddr1, sockaddr1.length |
cmp eax, -1 |
je bind_err |
mcall listen, [socketnum], 10 ; Backlog = 10 |
cmp eax, -1 |
je listen_err |
push str2 |
call [con_write_asciiz] |
mcall 10 |
mcall accept, [socketnum], sockaddr1, sockaddr1.length |
cmp eax, -1 |
je acpt_err |
mov [socketnum2], eax |
;; mcall close, [socketnum] |
mcall send, [socketnum2], hello, hello.length |
.loop: |
mcall 10 |
mcall recv, [socketnum2], buffer, buffer.length |
cmp eax, -1 |
je .loop |
mov byte [buffer + eax], 0 |
push buffer |
call [con_write_asciiz] |
jmp .loop |
acpt_err: |
push str8 |
call [con_write_asciiz] |
jmp done |
listen_err: |
push str3 |
call [con_write_asciiz] |
jmp done |
bind_err: |
push str4 |
call [con_write_asciiz] |
jmp done |
sock_err: |
push str6 |
call [con_write_asciiz] |
jmp done |
done: |
call [con_getch2] |
push 1 |
call [con_exit] |
exit: |
mcall -1 |
; data |
title db 'TCP stream server - test',0 |
str1 db 'Opening socket',10, 0 |
str2 db 'Listening for incoming connections...',10,0 |
str3 db 'Listen error',10,10,0 |
str4 db 'Bind error',10,10,0 |
str5 db 'Setsockopt error.',10,10,0 |
str6 db 'Could not open socket',10,10,0 |
str7 db 'Got data!',10,10,0 |
str8 db 'Error accepting connection',10,10,0 |
hello db 'Hello world!',0 |
.length = $ - hello |
sockaddr1: |
dw AF_INET4 |
.port dw 0x1700 ; 23 |
.ip dd 0 |
rb 10 |
.length = $ - sockaddr1 |
; import |
align 4 |
@IMPORT: |
library console, 'console.obj' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz, 'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_printf, 'con_printf',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos' |
i_end: |
socketnum dd ? |
socketnum2 dd ? |
buffer rb BUFFERSIZE |
.length = BUFFERSIZE |
align 4 |
rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/telnet/telnet.asm |
---|
0,0 → 1,305 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; telnet.asm - Telnet client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
__DEBUG__ equ 0 |
__DEBUG_LEVEL__ equ 1 |
BUFFERSIZE equ 4096 |
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd s ; parameters |
dd 0 ; path |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../debug-fdo.inc' |
include '../network.inc' |
; entry point |
start: |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
; Check for parameters |
cmp byte [s], 0 |
jne resolve |
main: |
call [con_cls] |
; Welcome user |
push str1 |
call [con_write_asciiz] |
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
; check for exit |
test eax, eax |
jz done |
cmp byte [esi], 10 |
jz done |
resolve: |
; delete terminating '\n' |
mov esi, s |
@@: |
lodsb |
cmp al, 0x20 |
ja @r |
mov byte [esi-1], 0 |
call [con_cls] |
push str3 |
call [con_write_asciiz] |
push s |
call [con_write_asciiz] |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push s ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz fail |
; write results |
push str8 |
call [con_write_asciiz] |
; mov edi, esi |
; convert IP address to decimal notation |
mov eax, [esi+addrinfo.ai_addr] |
mov eax, [eax+sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
push eax |
call [inet_ntoa] |
; write result |
push eax |
call [con_write_asciiz] |
; free allocated memory |
push esi |
call [freeaddrinfo] |
push str9 |
call [con_write_asciiz] |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
cmp eax, -1 |
jz fail2 |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
mcall 40, 1 shl 7 ; + 7 |
call [con_cls] |
mcall 18, 7 |
push eax |
mcall 51, 1, thread, mem - 2048 |
pop ecx |
mcall 18, 3 |
mainloop: |
DEBUGF 1, 'TELNET: Waiting for events\n' |
mcall 10 |
DEBUGF 1, 'TELNET: EVENT %x !\n', eax |
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz exit |
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 |
cmp eax, -1 |
je mainloop |
DEBUGF 1, 'TELNET: got %u bytes of data !\n', eax |
mov esi, buffer_ptr |
lea edi, [esi + eax] |
mov byte [edi], 0 |
.scan_cmd: |
cmp byte [esi], 0xff ; Interpret As Command |
jne .no_cmd |
; TODO: parse options, for now, we will reply with 'WONT' to everything |
mov byte [esi + 1], 252 ; WONT |
add esi, 3 ; a command is always 3 bytes |
jmp .scan_cmd |
.no_cmd: |
cmp esi, buffer_ptr |
je .print_loop |
DEBUGF 1, 'TELNET: sending data\n' |
push esi edi |
sub esi, buffer_ptr |
mcall send, [socketnum], buffer_ptr, , 0 |
pop edi esi |
.print_loop: |
DEBUGF 1, 'TELNET: printloop\n' |
cmp esi, edi |
jae mainloop |
cmp byte [esi], 0x1b ; escape character |
jne .print_byte |
inc esi |
cmp word [esi], 0x485b ; move cursor to beginning |
jne @f |
inc esi |
inc esi |
DEBUGF 1, 'TELNET: resetting cursor \n' |
push 0 |
push 0 |
call [con_set_cursor_pos] |
jmp .print_loop |
@@: |
inc esi |
inc esi |
jmp .print_loop |
.print_byte: |
push dword 1 |
push esi ; next string to print |
inc esi |
call [con_write_string] |
jmp .print_loop |
fail2: |
push str6 |
call [con_write_asciiz] |
jmp fail.wait |
fail: |
push str5 |
call [con_write_asciiz] |
.wait: |
push str10 |
call [con_write_asciiz] |
call [con_getch2] |
jmp main |
done: |
push 1 |
call [con_exit] |
exit: |
mcall close, [socketnum] |
mcall -1 |
thread: |
mcall 40, 0 |
.loop: |
call [con_getch2] |
mov byte [send_data], al |
mcall send, [socketnum], send_data, 1 |
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jz .loop |
mcall -1 |
; data |
title db 'Telnet',0 |
str1 db 'Telnet for KolibriOS v0.11',10,10,'Please enter URL of telnet server (for example: towel.blinkenlights.nl)',10,10,0 |
str2 db '> ',0 |
str3 db 'Connecting to: ',0 |
str4 db 10,0 |
str5 db 10,'Name resolution failed.',10,0 |
str6 db 10,'Could not open socket.',10,0 |
str8 db ' (',0 |
str9 db ')',10,0 |
str10 db 'Push any key to continue.',0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0x1700 ; 23 |
.ip dd 0 |
rb 10 |
include_debug_strings ; ALWAYS present in data section |
; import |
align 4 |
@IMPORT: |
library network, 'network.obj', console, 'console.obj' |
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz, 'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos',\ |
con_write_string, 'con_write_string',\ |
con_get_flags, 'con_get_flags' |
i_end: |
socketnum dd ? |
buffer_ptr rb BUFFERSIZE+1 |
send_data rb 100 |
s rb 1024 |
rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/vncc/vncc.asm |
---|
0,0 → 1,283 |
; |
; |
; VNC Client for kolibrios by hidnplayr |
; |
; hidnplayr@gmail.com |
; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 0x01 ; header version |
dd START ; start of code |
dd I_END ; size of image |
dd IM_END ; memory for app |
dd IM_END ; esp |
dd 0x0 , 0x0 ; I_Param , I_Path |
__DEBUG__ equ 1 |
__DEBUG_LEVEL__ equ 1 |
STRLEN = 64 ; password and server max length |
xpos = 4 ; coordinates of image |
ypos = 22 ; |
TIMEOUT = 5 ; timeout in seconds |
include '../macros.inc' |
include '../debug-fdo.inc' |
include '../proc32.inc' |
include '../dll.inc' |
include '../struct.inc' |
include '../network.inc' |
include 'structs.inc' |
include 'logon.inc' |
include 'raw.inc' |
include 'thread.inc' |
START: |
mcall 68, 11 ; init heap |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
call red_logon |
mcall 40, 0 ; no events |
mcall 67, 0, 0, 0, 0 ; resize the window (hide it) |
mcall 51, 1, thread_start, thread_stack |
DEBUGF 1,'Thread created: %u\n', eax |
@@: |
mcall 5, 10 |
cmp byte [thread_ready], 0 |
je @r |
mcall 40, 100111b ; mouse, button, key, redraw |
mov edx, dword [screen] |
movzx esi, dx |
shr edx, 16 |
add edx, 2*xpos |
add esi, ypos+xpos |
mcall 67, 10, 10 ; resize the window |
mainloop: |
mcall 23, 50 ; wait for event, 0,5s timeout |
dec eax |
jz redraw |
dec eax |
jz key |
dec eax |
jz button |
sub eax, 3 |
jz mouse |
jmp mainloop |
key: |
DEBUGF 1,'Sending key event\n' |
mcall 2 |
mov byte [keyevent.key+3], ah |
mcall send, [socketnum], keyevent, 8, 0 |
jmp mainloop |
mouse: |
DEBUGF 1,'Sending mouse event\n' |
mcall 37, 1 ; get mouse pos |
sub eax, xpos shl 16 + ypos |
bswap eax |
mov [pointerevent.x], ax |
shr eax, 16 |
mov [pointerevent.y], ax |
mcall 37, 2 ; get mouse buttons |
test al, 00000010b ; test if right button was pressed (bit 1 in kolibri) |
jz @f |
add al, 00000010b ; in RFB protocol it is bit 2, so if we add bit 2 again, we'll get bit 3 and bit 1 will remain the same |
@@: |
mov [pointerevent.mask],al |
mcall send, [socketnum], pointerevent, 6, 0 |
jmp mainloop |
redraw: |
DEBUGF 1,'Drawing window\n' |
mcall 12, 1 |
mov ebx, dword[screen] |
movzx ecx, bx |
shr ebx, 16 |
mov edx, 0x74ffffff |
mov edi, name |
mcall 0 ; draw window |
call drawbuffer |
mcall 12, 2 |
jmp mainloop |
drawbuffer: |
mcall 7, framebuffer_data, dword[screen], 0 |
ret |
button: |
mcall 17 ; get id |
exit: |
DEBUGF 1, 'Closing time!\n' |
mcall close, [socketnum] |
mcall -1 |
no_rfb: |
DEBUGF 1, 'This is no vnc server!\n' |
jmp exit |
invalid_security: |
DEBUGF 1, 'Security error: %s\n', receive_buffer+5 |
jmp exit |
; DATA AREA |
include_debug_strings ; ALWAYS present in data section |
handshake db 'RFB 003.003', 10 |
shared db 0 |
beep db 0x85,0x25,0x85,0x40,0 |
pixel_format32 db 0 ; setPixelformat |
rb 3 ; padding |
.bpp db 32 ; bits per pixel |
.depth db 32 ; depth |
.big_endian db 0 ; big-endian flag |
.true_color db 1 ; true-colour flag |
.red_max db 0,255 ; red-max |
.green_max db 0,255 ; green-max |
.blue_max db 0,255 ; blue-max |
.red_shif db 0 ; red-shift |
.green_shift db 8 ; green-shift |
.blue_shift db 16 ; blue-shift |
rb 3 ; padding |
pixel_format16 db 0 ; setPixelformat |
rb 3 ; padding |
.bpp db 16 ; bits per pixel |
.depth db 15 ; depth |
.big_endian db 0 ; big-endian flag |
.true_color db 1 ; true-colour flag |
.red_max db 0,31 ; red-max |
.green_max db 0,31 ; green-max |
.blue_max db 0,31 ; blue-max |
.red_shif db 0 ; red-shift |
.green_shift db 5 ; green-shift |
.blue_shift db 10 ; blue-shift |
rb 3 ; padding |
pixel_format8 db 0 ; setPixelformat |
rb 3 ; padding |
.bpp db 8 ; bits per pixel |
.depth db 6 ; depth |
.big_endian db 0 ; big-endian flag |
.true_color db 1 ; true-colour flag |
.red_max db 0,3 ; red-max |
.green_max db 0,3 ; green-max |
.blue_max db 0,3 ; blue-max |
.red_shif db 0 ; red-shift |
.green_shift db 2 ; green-shift |
.blue_shift db 4 ; blue-shift |
rb 3 ; padding |
encodings db 2 ; setEncodings |
rb 1 ; padding |
db 1,0 ; number of encodings |
db 0,0,0,0 ; raw encoding (DWORD, Big endian order) |
db 1,0,0,0 ; Copyrect encoding |
fbur db 3 ; frame buffer update request |
.inc db 0 ; incremental |
.x dw 0 |
.y dw 0 |
.width dw 0 |
.height dw 0 |
keyevent db 4 ; keyevent |
.down db 0 ; down-flag |
dw 0 ; padding |
.key dd 0 ; key |
pointerevent db 5 ; pointerevent |
.mask db 0 ; button-mask |
.x dw 0 ; x-position |
.y dw 0 ; y-position |
sockaddr1: |
dw AF_INET4 |
.port dw 0x0c17 ; 5900 |
.ip dd 0 |
rb 10 |
thread_ready db 0 |
; import |
align 4 |
@IMPORT: |
library network, 'network.obj' |
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
name db 'VNC client', 0 |
I_END: |
socketnum dd ? |
datapointer dd ? |
frame: |
.width dw ? |
.height dw ? |
.x dw ? |
.y dw ? |
screen: |
.height dw ? |
.width dw ? |
receive_buffer rb 5*1024*1024 ; 5 mb buffer for received data (incoming frbupdate etc) |
framebuffer_data rb 1024*768*3 ; framebuffer |
rb 0x1000 |
thread_stack: |
rb 0x1000 |
IM_END: |
/kernel/branches/net/applications/vncc/logon.inc |
---|
0,0 → 1,257 |
red_logon: |
call draw_window_logon ; at first, draw the window |
still_logon: ; main cycle of application begins here |
mov eax,10 ; wait here for event |
mcall |
checkevent_logon: ; Check what event was called _logon: this will be used to return from textbox focus |
dec eax ; redraw request ? |
jz red_logon |
dec eax ; key in buffer ? |
jz key_logon |
dec eax ; button in buffer ? |
jz button_logon |
jmp still_logon |
key_logon: ; key event handler |
mov al,2 ; eax was zero so will now be 2 |
mcall ; just read it and ignore |
cmp ah,13 |
jne still_logon ; return to main loop |
ret ; enter key was pressed => return to logon |
button_logon: ; eax was zero so will now be 17 |
mov al,17 ; get id |
mcall |
cmp ah,1 ; close ? |
jz close_logon |
cmp ah,2 ; logon ? |
je connect_logon |
cmp ah,5 ; first ? |
jz dstbtn_logon |
srcbtn_logon: |
mov dword[addr],first |
jmp rk_logon |
dstbtn_logon: |
mov dword[addr],second |
rk_logon: |
mov edi,[addr] ; load the address of the string |
xor al,al ; mov al,0 ; the symbol we will search for |
mov ecx,STRLEN+1 ; length of the string (+1) |
cld ; search forward |
repne scasb ; do search now |
inc ecx ; we've found a zero or ecx became 0 |
mov eax,STRLEN+1 |
sub eax,ecx ; eax = address of <0> character |
mov [temp],eax ; position |
cmp dword[addr],dword second |
jne @f |
mov dword [passlen],eax |
@@: |
call print_text_logon |
mov edi,[addr] ; address of string |
add edi,[temp] ; cursor position |
.waitev_logon: |
mov eax,10 ; wait for event |
mcall |
cmp eax,2 ; button presed ? |
jne checkevent_logon ; a key is pressed or redraw is nessesary, goto checkevent |
mcall ; eax = 2, read button |
shr eax,8 |
cmp eax,8 |
jnz .nobs_logon ; BACKSPACE |
cmp edi,[addr] |
jz .waitev_logon |
dec edi |
mov byte[edi],0 |
cmp dword[addr],second |
jne @f |
dec [passlen] |
@@: |
call print_text_logon |
jmp .waitev_logon |
.nobs_logon: |
cmp eax,13 ; ENTER |
je still_logon |
cmp eax,192 |
jne .noclear_logon |
xor al,al |
mov edi,[addr] |
mov ecx,STRLEN |
rep stosb |
mov edi,[addr] |
call print_text_logon |
jmp .waitev_logon |
.noclear_logon: |
mov [edi],al |
cmp dword[addr],second |
jne @f |
inc [passlen] |
@@: |
call print_text_logon |
inc edi |
mov esi,[addr] |
add esi,STRLEN |
cmp esi,edi |
jnz .waitev_logon |
jmp still_logon |
; print strings (source & destination) |
print_text_logon: |
pusha |
mov eax, 8 |
mov ebx, 105*65536+200 |
mov ecx, 31*65536+13 |
mov edx, 4 |
mov esi, 0xEBEBEB |
mcall |
cmp byte[mode],0 |
je @f |
mov ecx, 49*65536+12 |
inc edx |
mcall |
@@: |
mov eax, 4 ; function 4 _logon: write text to window |
mov ebx, 107*65536+34 ; [x start] *65536 + [y start] |
xor ecx, ecx ; color of text RRGGBB |
mov edx, first ; pointer to text beginning |
mov esi, STRLEN ; text length |
mcall |
cmp byte[mode],0 |
je dont_draw_pass |
add ebx,16 |
mov edi,[passlen] |
@@: |
cmp edi,0 |
jle dont_draw_pass |
dec edi |
mov edx, passchar |
mov esi, 1 |
mcall |
add ebx,6*65536 |
jmp @r |
dont_draw_pass: |
popa |
ret |
close_logon: |
or eax,-1 |
mcall |
connect_logon: |
ret |
draw_window_logon: |
mcall 12, 1 ; start window draw |
pusha |
; DRAW WINDOW |
xor eax, eax ; function 0 _logon: define and draw window |
mov ebx, 160*65536+330 ; [x start] *65536 + [x size] |
mov ecx, 160*65536+100 ; [y start] *65536 + [y size] |
mov edx, 0x13DDDDDD ; color of work area RRGGBB |
mov edi, title ; WINDOW LABEL |
mcall |
mov eax, 8 ; LOGON BUTTON |
mov ebx, 220*65536+85 |
mov ecx, 63*65536+16 |
mov edx, 2 |
mov esi, 0xCCCCCC |
mcall |
call print_text_logon |
cmp byte[mode], 0 |
je servermode_ |
mov eax, 4 ; function 4 write text to window |
mov ebx, 25*65536+33 ; [x start] *65536 + [y start] |
xor ecx, ecx |
mov edx, userstr ; pointer to text beginning |
mov esi, passstr-userstr ; text length |
mcall |
add bl,19 |
mov edx, passstr ; pointer to text beginning |
mov esi, connectstr-passstr ; text length |
mcall |
jmp drawtherest_ |
servermode_: |
mov eax, 4 ; function 4 write text to window |
mov ebx, 25*65536+33 ; [x start] *65536 + [y start] |
xor ecx, ecx |
mov edx, serverstr ; pointer to text beginning |
mov esi, userstr-serverstr ; text length |
mcall |
drawtherest_: |
mov ebx, 240*65536+67 ; [x start] *65536 + [y start] |
mov edx, connectstr ; pointer to text beginning |
mov esi, connect_e-connectstr ; text length |
mcall |
popa |
inc ebx |
mcall |
ret |
; DATA AREA |
title db 'Kolibrios VNC client by HIDNPLAYR',0 |
first: db '192.168.1.5' |
rb STRLEN |
second: rb STRLEN |
passchar db '*' |
passlen dd 0 |
addr dd 0 |
temp dd 0 |
mode db 0 ; 0 = connection details, 1 = authentication |
serverstr: db 'server:' |
userstr: db 'username:' |
passstr: db 'password:' |
connectstr: db 'connect !' |
connect_e: |
I_END_logon: |
/kernel/branches/net/applications/vncc/raw.inc |
---|
0,0 → 1,153 |
encoding_raw: |
DEBUGF 1,'RAW\n' |
mov ax,[frame.y] ; |
mov bx,[screen.width] ; |
mul bx ; |
shl edx,16 ; |
mov dx,ax ; [screen.width]*[frame.y] |
movzx eax,[frame.x] |
add edx,eax ; [screen.width]*[frame.y]+[frame.x] |
mov eax,3 ; |
mul edx ; ([screen.width]*[frame.y]+[frame.x])*3 |
add eax,framebuffer_data ; |
push eax ; framebuffer_data+([screen.width]*[frame.y]+[frame.x])*3 |
mov ax,[frame.width] ; |
mov bx,3 ; |
mul bx ; |
shl edx,16 ; |
mov dx,ax ; [frame.width]*3 |
pop eax ; |
add edx,eax ; framebuffer_data+([screen.width]*[frame.y]+[frame.x])*3+[frame.width]*3 |
push eax ; |
push edx ; |
mov ax,[frame.height] ; |
dec ax ; |
mov bx,3 ; |
mul bx ; |
mov bx,[screen.width] ; |
mul bx ; |
shl edx,16 ; |
mov dx,ax ; |
mov ecx,edx ; |
pop edx ; |
add ecx,edx ; mov ecx,edx+([frame.height]-1)*[screen.width]*3 |
pop ebx |
.pixelloop32: |
cmp ebx,ecx |
jge next_rectangle |
; add esi,2 ; 32 bit code RAW - OK |
; mov al,[esi] ; |
; mov [ebx],al ; |
; inc ebx ; |
; dec esi ; |
; ; |
; mov al,[esi] ; |
; mov [ebx],al ; |
; inc ebx ; |
; dec esi ; |
; ; |
; mov al,[esi] ; |
; mov [ebx],al ; |
; inc ebx ; |
; add esi,4 ; |
; push ecx ; 16 bit code RAW |
; mov cl,51 |
; |
; mov ax,[esi] ; |
; xchg al,ah |
; and al,00011111b ; |
; xchg al,ah |
; mul cl |
; mov [ebx],al ; |
; inc ebx ; |
; |
; mov ax,[esi] ; |
; xchg al,ah |
; shr ax,5 ; |
; xchg al,ah |
; and al,00011111b ; |
; mul cl |
; mov [ebx],al ; |
; inc ebx ; |
; |
; mov ax,[esi] ; |
; xchg al,ah |
; shr ax,10 ; |
; and al,00011111b ; |
; mul cl |
; mov [ebx],al ; |
; inc ebx ; |
; |
; inc esi ; |
; inc esi ; |
; pop ecx |
push ecx ; 8 bit code RAW - OK |
mov cl,85 ; |
; |
mov al,[esi] ; |
shr al,4 ; |
and al,3 ; |
mul cl ; |
mov [ebx],al ; |
inc ebx ; |
; |
mov al,[esi] ; |
shr al,2 ; |
and al,3 ; |
mul cl ; |
mov [ebx],al ; |
inc ebx ; |
; |
mov al,[esi] ; |
and al,3 ; |
mul cl ; |
mov byte[ebx],al ; |
inc ebx ; |
inc esi ; |
pop ecx ; |
cmp ebx,edx |
jl .pixelloop32 |
push edx |
push ebx |
mov ax,[screen.width] |
mov bx,3 |
mul bx |
shl edx,16 |
mov dx,ax |
mov eax,edx |
pop ebx |
pop edx |
add ebx,eax ; eax = [screen.width]*3 |
add edx,eax |
push edx |
push ebx |
mov ax,[frame.width] |
mov bx,3 |
mul bx |
shl edx,16 |
mov dx,ax |
mov eax,edx |
pop ebx |
pop edx |
sub ebx,eax ; eax = [frame.width]*3 |
jmp .pixelloop32 |
/kernel/branches/net/applications/vncc/structs.inc |
---|
0,0 → 1,22 |
struct pixel_format |
bpp db ? |
depth db ? |
big_endian db ? |
true_color db ? |
red_max dw ? |
green_max dw ? |
blue_max dw ? |
red_shift db ? |
green_shift db ? |
blue_shift db ? |
padding rb 3 |
ends |
struct framebuffer |
width dw ? |
height dw ? |
pixelformat pixel_format |
name_length dd ? |
name rb 256 |
ends |
/kernel/branches/net/applications/vncc/thread.inc |
---|
0,0 → 1,239 |
thread_start: |
DEBUGF 1, 'I am the thread!\n' |
mcall 40, 1 shl 7 |
; resolve name |
push esp ; reserve stack place |
invoke getaddrinfo, first, 0, 0, esp |
pop esi |
; test for error |
test eax, eax |
jnz exit |
mov eax, [esi+addrinfo.ai_addr] |
mov eax, [eax+sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
; DEBUGF 1, 'Connecting to %u.%u.%u.%u:%u\n', \ |
; [server_ip]:1, [server_ip+1]:1, \ |
; [server_ip+2]:1, [server_ip+3]:1, \ |
; [server_port]:2 |
mcall socket, AF_INET4, SOCK_STREAM, 0 |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
call wait_for_data |
cmp dword [receive_buffer], 'RFB ' |
jne no_rfb |
DEBUGF 1, 'received: %s\n', receive_buffer |
mcall send, [socketnum], handshake, 12, 0 |
DEBUGF 1, 'Sending handshake: protocol version\n' |
call wait_for_data |
cmp dword [receive_buffer], 0x00000000 |
je invalid_security |
cmp dword [receive_buffer], 0x01000000 |
je no_security |
cmp dword [receive_buffer], 0x02000000 |
je vnc_security |
jmp exit |
vnc_security: |
mov byte[mode], 1 |
call red_logon |
no_security: |
mcall send, [socketnum], shared, 1, 0 |
DEBUGF 1, 'Sending handshake: shared session?\n' |
mcall 23, 100*TIMEOUT |
call wait_for_data ; now the server should send init message |
DEBUGF 1, 'Serverinit: bpp: %u depth: %u bigendian: %u truecolor: %u\n', \ |
[receive_buffer+framebuffer.pixelformat.bpp]:1, \ |
[receive_buffer+framebuffer.pixelformat.depth]:1, \ |
[receive_buffer+framebuffer.pixelformat.big_endian]:1, \ |
[receive_buffer+framebuffer.pixelformat.true_color]:1 |
mov eax, dword [receive_buffer] |
mov dword [fbur.width], eax |
bswap eax |
mov dword [screen], eax |
mcall send, [socketnum], pixel_format8, 20, 0 |
DEBUGF 1, 'Sending pixel format\n' |
call read_data |
; eth.write_tcp [socket],8,encodings |
; DEBUGF 1,'Sending encoding info\n' |
; call read_data |
mov byte [thread_ready], 1 |
request_rfb: |
mov [fbur.inc], 2 |
mcall send, [socketnum], fbur, 10, 0 |
thread_loop: |
mcall 23, 100 |
call read_data ; Read the data into the buffer |
; cmp eax, 2 |
; jb mainloop |
DEBUGF 1,'Data received, %u bytes\n', eax |
cmp byte [receive_buffer],0 |
je framebufferupdate |
cmp byte [receive_buffer],1 |
je setcolourmapentries |
cmp byte [receive_buffer],2 |
je bell |
cmp byte [receive_buffer],3 |
je servercuttext |
jmp thread_loop |
align 4 |
framebufferupdate: |
mov ax, word [receive_buffer+2] |
xchg al, ah |
mov di, ax |
DEBUGF 1, 'Framebufferupdate: %u frames\n', di |
mov esi, receive_buffer+4 |
jmp rectangle_loop |
next_rectangle: |
call drawbuffer |
dec di |
test di, di |
jz request_rfb |
rectangle_loop: |
mov edx, [esi] |
bswap edx |
mov ebx, edx |
shr edx, 16 |
mov [frame.x], dx |
mov [frame.y], bx |
add esi, 4 |
mov ecx, [esi] |
bswap ecx |
mov eax, ecx |
shr ecx, 16 |
mov [frame.width], cx |
mov [frame.height], ax |
add esi, 4 |
mov eax, [esi] |
add esi, 4 |
mov ebx, esi |
sub ebx, receive_buffer+12 |
DEBUGF 1, 'frame: width=%u height=%u x=%u y=%u offset:%u encoding:',\ |
[frame.width]:2, [frame.height]:2, [frame.x]:2, [frame.y]:2, ebx |
cmp eax, 0 |
je encoding_raw |
; cmp eax, 1 |
; je encoding_copyrect |
cmp eax, 2 |
je encoding_RRE |
cmp eax, 5 |
je encoding_hextile |
cmp eax, 16 |
je encoding_ZRLE |
mov ebx, esi |
sub ebx, receive_buffer+8 |
DEBUGF 1, '\nunknown encoding: %u (offset %u)\n', eax, ebx |
jmp bell |
jmp thread_loop |
encoding_RRE: |
DEBUGF 1, 'RRE\n' |
jmp next_rectangle |
encoding_hextile: |
DEBUGF 1, 'hextile\n' |
jmp next_rectangle |
encoding_ZRLE: |
DEBUGF 1, 'ZRLE\n' |
jmp next_rectangle |
setcolourmapentries: |
DEBUGF 1, 'Server sent SetColourMapEntries message\n' |
jmp thread_loop |
bell: |
mcall 55, 55, , , beep |
jmp thread_loop |
servercuttext: |
DEBUGF 1, 'Server cut text\n' |
jmp thread_loop |
read_data: |
mov [datapointer], receive_buffer |
.loop: |
mcall 23, 100*TIMEOUT |
mcall recv, [socketnum], [datapointer], 4096, 0 |
cmp eax, -1 |
je .done |
add [datapointer], eax |
cmp eax, 4096 |
je .loop |
.done: |
mov eax, [datapointer] |
sub eax, receive_buffer |
ret |
wait_for_data: |
mcall 23, 500 |
mcall recv, [socketnum], receive_buffer, 4096, 0 |
cmp eax, -1 |
je wait_for_data |
test eax, eax |
jz wait_for_data |
ret |
/kernel/branches/net/applications/pppoe/pppoe.asm |
---|
0,0 → 1,362 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; pppoe.asm - PPPoE dialer for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
use32 |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd 0 ; parameters |
dd 0 ; path |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../network.inc' |
include '../struct.inc' |
; Ethernet protocol numbers |
ETHER_PPP_DISCOVERY = 0x6388 |
ETHER_PPP_SESSION = 0x6488 |
; PPP protocol numbers |
PPP_LCP = 0x21c0 ; Link Configure Protocol |
PPP_CBCP = 0x29c0 ; CallBack Control Protocol |
PPP_PAP = 0x23c0 ; Password Authenication Protocol packet |
PPP_CHAP = 0x23c2 ; Challenge Handshake Authentication Protocol |
PPP_IPCP = 0x2180 ; Internet Protocol Configure Protocol (maybe this should be in kernel?) |
PPP_CCP = 0xfd80 ; Compression Configure Protocol |
; PPP Active Discovery... |
PPPoE_PADI = 0x09 ; .. Initiation |
PPPoE_PADO = 0x07 ; .. Offer |
PPPoE_PADR = 0x19 ; .. Request |
PPPoE_PADS = 0x65 ; .. Session-confirmation |
PPPoE_PADT = 0xa7 ; .. Terminate |
TAG_EOL = 0x0000 |
TAG_SERVICE_NAME= 0x0101 |
TAG_AC_NAME = 0x0201 |
TAG_HOST_UNIQ = 0x0301 |
TAG_AC_COOKIE = 0x0401 |
LCP_config_request = 1 |
LCP_config_ack = 2 |
LCP_config_nak = 3 |
LCP_config_reject = 4 |
LCP_terminate_request = 5 |
LCP_terminate_ack = 6 |
LCP_code_reject = 7 |
LCP_protocol_reject = 8 |
LCP_echo_request = 9 |
LCP_echo_reply = 10 |
LCP_discard_request = 11 |
struct ETH_frame |
DestMac dp ? |
SrcMac dp ? |
Type dw ? |
ends |
struct PPPoE_frame ETH_frame |
VersionAndType db ? |
Code db ? |
SessionID dw ? |
Length dw ? ; Length of payload, does NOT include the length PPPoE header. |
Payload rb 0 |
ends |
struct PPP_frame PPPoE_frame |
Protocol dw ? |
ends |
struct LCP_frame PPP_frame |
LCP_Code db ? |
LCP_Identifier db ? |
LCP_Length dw ? |
LCP_Data rb 0 |
ends |
; entry point |
start: |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
main: |
mcall 40, 1 shl 7 |
call [con_cls] |
; Welcome user |
push str1 |
call [con_write_asciiz] |
mcall socket, 777, 3, 666 |
mov [socketnum], eax |
mcall send, [socketnum], PADI, PADI.length, 0 |
mainloop: |
mcall 10 |
call [con_get_flags] |
test eax, 0x200 ; con window closed? |
jnz close_conn |
mcall recv, [socketnum], buffer, 4096 |
cmp eax, sizeof.PPPoE_frame |
jb mainloop |
cmp word [buffer + ETH_frame.Type], ETHER_PPP_SESSION |
je SESSION_input |
cmp word [buffer + ETH_frame.Type], ETHER_PPP_DISCOVERY |
jne mainloop |
cmp [buffer + PPPoE_frame.Code], PPPoE_PADO |
je pado |
cmp [buffer + PPPoE_frame.Code], PPPoE_PADS |
je pads |
cmp [buffer + PPPoE_frame.Code], PPPoE_PADT |
je padt |
jmp mainloop |
pado: |
push str2 |
call [con_write_asciiz] |
lea esi, [buffer + ETH_frame.SrcMac] ; source mac -> dest mac |
lea edi, [buffer + ETH_frame.DestMac] |
movsw |
movsd |
mov byte [buffer + PPPoE_frame.Code], PPPoE_PADR ; change packet type to PADR |
mov al, byte [buffer + PPPoE_frame.Length + 1] ; get packet size |
mov ah, byte [buffer + PPPoE_frame.Length + 0] |
movzx esi, ax |
add esi, sizeof.PPPoE_frame |
mcall send, [socketnum], buffer, , 0 ; now send it! |
jmp mainloop |
pads: |
push str3 |
call [con_write_asciiz] |
mov edx, dword [buffer + ETH_frame.SrcMac] ; source mac -> dest mac |
mov si, word [buffer + ETH_frame.SrcMac + 4] |
mov dword [PADT.mac], edx |
mov word [PADT.mac + 4], si |
mov cx, word [buffer + PPPoE_frame.SessionID] ; and Session ID |
mov [PADT.sid], cx |
mcall 76, API_PPPOE + 0 ; Start PPPoE session |
jmp mainloop |
padt: |
push str4 |
call [con_write_asciiz] |
mcall 76, API_PPPOE + 1 ; Stop PPPoE session |
exit: |
mcall close, [socketnum] |
mcall -1 |
close_conn: |
mcall send, [socketnum], PADT, PADT.length, 0 |
jmp exit |
SESSION_input: |
mov ax, word[buffer + PPP_frame.Protocol] |
cmp ax, PPP_LCP |
je LCP_input |
cmp ax, PPP_CBCP |
je CBCP_input |
cmp ax, PPP_PAP |
je PAP_input |
cmp ax, PPP_CHAP |
je CHAP_input |
cmp ax, PPP_IPCP |
je IPCP_input |
cmp ax, PPP_CCP |
je CCP_input |
jmp mainloop |
LCP_input: |
stdcall con_write_asciiz, str_lcp |
cmp [buffer + LCP_frame.LCP_Code], LCP_echo_request |
je .echo |
.dump: |
jmp mainloop |
.echo: |
mov [buffer + LCP_frame.LCP_Code], LCP_echo_reply |
lea esi, [buffer + ETH_frame.SrcMac] ; source mac -> dest mac |
lea edi, [buffer + ETH_frame.DestMac] |
movsw |
movsd |
mov esi, eax |
mcall send, [socketnum], buffer, , 0 ; now send it back! |
jmp mainloop |
CBCP_input: |
stdcall con_write_asciiz, str_cbcp |
jmp mainloop |
PAP_input: |
stdcall con_write_asciiz, str_pap |
jmp mainloop |
CHAP_input: |
stdcall con_write_asciiz, str_chap |
jmp mainloop |
IPCP_input: |
stdcall con_write_asciiz, str_ipcp |
jmp mainloop |
CCP_input: |
stdcall con_write_asciiz, str_ccp |
jmp mainloop |
; data |
title db 'PPPoE',0 |
str1 db 'Sending PADI',13,10,0 |
str2 db 'Got PADO',13,10,'Sending PADR',13,10,0 |
str3 db 'Got PADS',13,10,'starting PPPoE session',13,10,0 |
str4 db 'Got PADT - connection terminated by Access Concentrator',13,10,0 |
str_lcp db 'Got LCP packet',13,10,0 |
str_cbcp db 'got CBCP packet',13,10,0 |
str_pap db 'got PAP packet',13,10,0 |
str_chap db 'got CHAP packet',13,10,0 |
str_ipcp db 'got IPCP packet',13,10,0 |
str_ccp db 'got CCP packet',13,10,0 |
PADI: |
dp 0xffffffffffff ; dest mac: broadcast |
dp 0 ; source mac (overwritten by kernel) |
dw ETHER_PPP_DISCOVERY ; type |
db 0x11 ; Version and Type |
db PPPoE_PADI ; Code |
dw 0 ; session ID |
dw 20 shl 8 ; Payload Length |
dw TAG_SERVICE_NAME ; tag |
dw 0x0000 ; length |
dw TAG_HOST_UNIQ ; tag |
dw 0x0c00 ; length = 12 bytes |
dd 0xdead ; some random id |
dd 0xbeef |
dd 0x1337 |
.length = $ - PADI |
PADT: |
.mac dp 0 ; Dest mac, to be filled in |
dp 0 ; source mac (overwritten by kernel) |
dw ETHER_PPP_DISCOVERY ; Type |
db 0x11 ; Version and Type |
db PPPoE_PADT ; Code: terminate connection |
.sid dw 0 ; session id, to be filled in |
dw 0 ; PAyload length = 0 |
.length = $ - PADT |
; import |
align 4 |
@IMPORT: |
library console, 'console.obj' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz, 'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos',\ |
con_write_string, 'con_write_string',\ |
con_get_flags, 'con_get_flags' |
i_end: |
socketnum dd ? |
buffer rb 4096 |
rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/icmp/icmp.inc |
---|
0,0 → 1,77 |
; ICMP types & codes |
ICMP_ECHOREPLY equ 0 ; echo reply message |
ICMP_UNREACH equ 3 |
ICMP_UNREACH_NET equ 0 ; bad net |
ICMP_UNREACH_HOST equ 1 ; bad host |
ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol |
ICMP_UNREACH_PORT equ 3 ; bad port |
ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop |
ICMP_UNREACH_SRCFAIL equ 5 ; src route failed |
ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net |
ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host |
ICMP_UNREACH_ISOLATED equ 8 ; src host isolated |
ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access |
ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto |
ICMP_UNREACH_TOSNET equ 11 ; bad tos for net |
ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host |
ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib |
ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. |
ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff |
ICMP_SOURCEQUENCH equ 4 ; Packet lost, slow down |
ICMP_REDIRECT equ 5 ; shorter route, codes: |
ICMP_REDIRECT_NET equ 0 ; for network |
ICMP_REDIRECT_HOST equ 1 ; for host |
ICMP_REDIRECT_TOSNET equ 2 ; for tos and net |
ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host |
ICMP_ALTHOSTADDR equ 6 ; alternate host address |
ICMP_ECHO equ 8 ; echo service |
ICMP_ROUTERADVERT equ 9 ; router advertisement |
ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement |
ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing |
ICMP_ROUTERSOLICIT equ 10 ; router solicitation |
ICMP_TIMXCEED equ 11 ; time exceeded, code: |
ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit |
ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass |
ICMP_PARAMPROB equ 12 ; ip header bad |
ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr |
ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent |
ICMP_PARAMPROB_LENGTH equ 2 ; bad length |
ICMP_TSTAMP equ 13 ; timestamp request |
ICMP_TSTAMPREPLY equ 14 ; timestamp reply |
ICMP_IREQ equ 15 ; information request |
ICMP_IREQREPLY equ 16 ; information reply |
ICMP_MASKREQ equ 17 ; address mask request |
ICMP_MASKREPLY equ 18 ; address mask reply |
ICMP_TRACEROUTE equ 30 ; traceroute |
ICMP_DATACONVERR equ 31 ; data conversion error |
ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect |
ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you |
ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here |
ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req |
ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply |
ICMP_SKIP equ 39 ; SKIP |
ICMP_PHOTURIS equ 40 ; Photuris |
ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index |
ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed |
ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed |
virtual at 0 |
ICMP_Packet: |
.Type db ? |
.Code db ? |
.Checksum dw ? |
.Identifier dw ? |
.SequenceNumber dw ? |
.Data: |
end virtual |
/kernel/branches/net/applications/icmp/ping.asm |
---|
0,0 → 1,256 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ping.asm - ICMP echo client for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd I_END ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd s ; parameters |
dd 0 ; path |
BUFFERSIZE equ 1500 |
; useful includes |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../network.inc' |
include 'icmp.inc' |
start: |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push 25 |
push 80 |
push 25 |
push 80 |
call [con_init] |
; main loop |
cmp byte[s], 0 |
jne resolve |
main: |
; write prompt |
push str2 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
; check for exit |
test eax, eax |
jz done |
cmp byte [esi], 10 |
jz done |
; delete terminating '\n' |
push esi |
@@: |
lodsb |
test al, al |
jnz @b |
mov byte [esi-2], al |
pop esi |
resolve: |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push s ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz fail |
; convert IP address to decimal notation |
mov eax, [esi+addrinfo.ai_addr] |
mov eax, [eax+sockaddr_in.sin_addr] |
mov [sockaddr1.ip], eax |
push eax |
call [inet_ntoa] |
; write result |
mov [ip_ptr], eax |
push eax |
; free allocated memory |
push esi |
call [freeaddrinfo] |
push str4 |
call [con_write_asciiz] |
mcall socket, AF_INET4, SOCK_RAW, IPPROTO_ICMP |
cmp eax, -1 |
jz fail2 |
mov [socketnum], eax |
mcall connect, [socketnum], sockaddr1, 18 |
mcall 40, 1 shl 7 ; + 7 |
; call [con_cls] |
mov [count], 4 |
mainloop: |
push str3 |
call [con_write_asciiz] |
push [ip_ptr] |
call [con_write_asciiz] |
mcall 26,9 |
mov [time_reference], eax |
mcall send, [socketnum], icmp_packet, icmp_packet.length, 0 |
mcall 23, 300 ; 3 seconds time-out |
mcall 26,9 |
neg [time_reference] |
add [time_reference], eax |
mcall recv, [socketnum], buffer_ptr, BUFFERSIZE, 0 |
cmp eax, -1 |
je .no_response |
; validate the packet |
lea esi, [buffer_ptr + ICMP_Packet.Data] |
mov edi, icmp_packet.data |
mov ecx, 32/4 |
repe cmpsd |
jne .miscomp |
push [time_reference] |
push str7 |
call [con_printf] |
jmp continue |
.miscomp: |
sub edi, icmp_packet.data |
push edi |
push str9 |
call [con_printf] |
jmp continue |
.no_response: |
push str8 |
call [con_write_asciiz] |
continue: |
dec [count] |
jz done |
mcall 5, 100 ; wait a second |
inc [icmp_packet.id] |
jmp mainloop |
done: |
push str10 |
call [con_write_asciiz] |
call [con_getch2] |
push 1 |
call [con_exit] |
exit: |
mcall -1 |
fail: |
push str5 |
call [con_write_asciiz] |
jmp done |
fail2: |
push str6 |
call [con_write_asciiz] |
jmp done |
; data |
title db 'ICMP - echo client',0 |
str2 db '> ',0 |
str3 db 'Ping to ',0 |
str4 db 10,0 |
str5 db 'Name resolution failed.',10,0 |
str6 db 'Could not open socket',10,0 |
str7 db ' time= %u0ms',10,0 |
str8 db ' timeout!',10,0 |
str9 db ' miscompare at offset %u',10,0 |
str10 db 10,'Press any key to exit',0 |
sockaddr1: |
dw AF_INET4 |
.port dw 0 |
.ip dd 0 |
rb 10 |
time_reference dd ? |
ip_ptr dd ? |
count dd ? |
; import |
align 4 |
@IMPORT: |
library network, 'network.obj', console, 'console.obj' |
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz, 'con_write_asciiz', \ |
con_printf, 'con_printf', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets',\ |
con_cls, 'con_cls',\ |
con_getch2, 'con_getch2',\ |
con_set_cursor_pos, 'con_set_cursor_pos' |
socketnum dd ? |
icmp_packet: db 8 ; type |
db 0 ; code |
dw 0 ; |
.id dw 0x0000 ; identifier |
.seq dw 0x0001 ; sequence number |
.data db 'abcdefghijklmnopqrstuvwxyz012345678' |
.length = $ - icmp_packet |
I_END: |
buffer_ptr rb BUFFERSIZE |
s rb 1024 |
rb 4096 ; stack |
mem: |
/kernel/branches/net/applications/arpcfg/arpcfg.asm |
---|
0,0 → 1,156 |
; |
; ARPmanager for KolibriOS |
; |
; hidnplayr@gmail.com |
; |
format binary as "" |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
dd 0x01 ; header version |
dd START ; start of code |
dd IM_END ; size of image |
dd (I_END+0x100) ; memory for app |
dd (I_END+0x100) ; esp |
dd 0x0 , 0x0 ; I_Param , I_Icon |
include '../macros.inc' |
purge mov, add, sub |
include '../struct.inc' |
include '../network.inc' |
START: |
redraw: |
mcall 12, 1 |
mcall 0, 100 shl 16 + 520, 100 shl 16 + 240, 0x34bcbcbc, , str_name |
mcall 4, 25 shl 16 + 31, 0x80000000, str_legend |
mcall 12, 2 |
draw_stats: |
mov edx, 50 shl 16 + 50 |
mov [last], 0 |
.loop: |
mcall 76, API_ARP + 3, [last],,, arp_buf |
cmp eax, -1 |
je mainloop |
mcall 4, edx, 0x80000000, str_entry |
mov edx, ebx |
mov eax, 47 |
mov ebx, 0x00030000 |
mov esi, 0x40000000 |
mov edi, 0x00bcbcbc |
xor ecx, ecx |
mov cl, byte[arp_buf.IP+0] |
mcall |
mov cl, byte[arp_buf.IP+1] |
add edx, 24 shl 16 |
mcall |
mov cl, byte[arp_buf.IP+2] |
add edx, 24 shl 16 |
mcall |
mov cl, byte[arp_buf.IP+3] |
add edx, 24 shl 16 |
mcall |
mov ebx, 0x00020100 |
mov cl, byte[arp_buf.MAC+0] |
add edx, 36 shl 16 |
mcall |
mov cl, byte[arp_buf.MAC+1] |
add edx, 18 shl 16 |
mcall |
mov cl, byte[arp_buf.MAC+2] |
add edx, 18 shl 16 |
mcall |
mov cl, byte[arp_buf.MAC+3] |
add edx, 18 shl 16 |
mcall |
mov cl, byte[arp_buf.MAC+4] |
add edx, 18 shl 16 |
mcall |
mov cl, byte[arp_buf.MAC+5] |
add edx, 18 shl 16 |
mcall |
mov ebx, 0x00040000 |
mov cx, [arp_buf.status] |
add edx, 30 shl 16 |
mcall |
mov cx, [arp_buf.TTL] |
add edx, 60 shl 16 |
mcall |
add dx, 20 |
rol edx, 16 |
mov dx, 50 |
rol edx, 16 |
inc [last] |
jmp .loop |
mainloop: |
mcall 23,50 ; wait for event with timeout (0,5 s) |
cmp eax, 1 |
je redraw |
cmp eax, 2 |
je key |
cmp eax, 3 |
je button |
jmp draw_stats |
key: |
mcall 2 |
jmp mainloop |
button: ; button |
mcall 17 ; get id |
cmp ah, 1 |
je exit |
jmp redraw |
exit: |
mcall -1 |
; DATA AREA |
str_name db 'ARP manager', 0 |
str_legend db '# IP-address MAC-address Status TTL', 0 |
str_entry db ' . . . - - - - - s', 0 |
IM_END: |
last dd ? |
arp_buf ARP_entry |
I_END: |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/nslookup/nslookup.asm |
---|
0,0 → 1,136 |
format binary as "" |
use32 |
; standard header |
db 'MENUET01' ; signature |
dd 1 ; header version |
dd start ; entry point |
dd i_end ; initialized size |
dd mem ; required memory |
dd mem ; stack pointer |
dd 0 ; parameters |
dd 0 ; path |
; useful includes |
include '../macros.inc' |
purge mov,add,sub |
include '../proc32.inc' |
include '../dll.inc' |
include '../network.inc' |
; entry point |
start: |
; load libraries |
stdcall dll.Load, @IMPORT |
test eax, eax |
jnz exit |
; initialize console |
push 1 |
call [con_start] |
push title |
push -1 |
push -1 |
push -1 |
push -1 |
call [con_init] |
; main loop |
main: |
; write prompt |
push str1 |
call [con_write_asciiz] |
; read string |
mov esi, s |
push 256 |
push esi |
call [con_gets] |
; check for exit |
test eax, eax |
jz done |
cmp byte [esi], 10 |
jz done |
; delete terminating '\n' |
push esi |
@@: |
lodsb |
test al, al |
jnz @b |
mov byte [esi-2], al |
pop esi |
; resolve name |
push esp ; reserve stack place |
push esp ; fourth parameter |
push 0 ; third parameter |
push 0 ; second parameter |
push esi ; first parameter |
call [getaddrinfo] |
pop esi |
; test for error |
test eax, eax |
jnz fail |
; write results |
push str2 |
call [con_write_asciiz] |
mov edi, esi |
addrloop: |
; before all subsequent addresses print comma |
cmp edi, esi |
jz @f |
push str3 |
call [con_write_asciiz] |
@@: |
; convert IP address to decimal notation |
mov eax, [edi+addrinfo.ai_addr] |
pushd [eax+sockaddr_in.sin_addr] |
call [inet_ntoa] |
; write result |
push eax |
call [con_write_asciiz] |
; advance to next item |
mov edi, [edi+addrinfo.ai_next] |
test edi, edi |
jnz addrloop |
; free allocated memory |
push esi |
call [freeaddrinfo] |
; write newline and continue main loop |
push str4 |
@@: |
call [con_write_asciiz] |
jmp main |
fail: |
push str5 |
jmp @b |
done: |
push 1 |
call [con_exit] |
exit: |
mcall -1 |
; data |
title db 'Names resolver',0 |
str1 db 'Host name to resolve: ',0 |
str2 db 'IP address(es): ',0 |
str3 db ', ',0 |
str4 db 10,0 |
str5 db 'Name resolution failed.',10,0 |
; import |
align 4 |
@IMPORT: |
library network, 'network.obj', console, 'console.obj' |
import network, \ |
getaddrinfo, 'getaddrinfo', \ |
freeaddrinfo, 'freeaddrinfo', \ |
inet_ntoa, 'inet_ntoa' |
import console, \ |
con_start, 'START', \ |
con_init, 'con_init', \ |
con_write_asciiz, 'con_write_asciiz', \ |
con_exit, 'con_exit', \ |
con_gets, 'con_gets' |
i_end: |
s rb 256 |
align 4 |
rb 4096 ; stack |
mem: |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/applications/dll.inc |
---|
0,0 → 1,160 |
;----------------------------------------------------------------------------- |
proc mem.Alloc size ;///////////////////////////////////////////////////////// |
;----------------------------------------------------------------------------- |
push ebx ecx |
mov eax,[size] |
lea ecx,[eax+4+4095] |
and ecx, not 4095 |
mcall 68,12 |
test eax, eax |
jz @f |
add ecx,-4 |
mov [eax],ecx |
add eax,4 |
@@: |
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] |
mcall 68,13 |
pop ecx ebx |
@@: 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 esi,[esi+4] |
mov edi,s_libdir.fname |
@@: lodsb |
stosb |
or al,al |
jnz @b |
mcall 68,19,s_libdir |
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] |
xor eax,eax |
.next: or edx,edx |
jz .end |
cmp dword[edx],0 |
jz .end |
stdcall strcmp,[edx],[sz_name] |
test eax,eax |
jz .ok |
add edx,8 |
jmp .next |
.ok: mov eax,[edx+4] |
.end: ret |
endp |
proc strcmp, str1:dword,str2:dword |
push esi edi |
mov esi,[str1] |
mov edi,[str2] |
xor eax,eax |
@@: lodsb |
scasb |
jne .fail |
or al,al |
jnz @b |
jmp .ok |
.fail: or eax,-1 |
.ok: pop edi esi |
ret |
endp |
s_libdir: |
db '/sys/lib/' |
.fname rb 32 |
/kernel/branches/net/applications/struct.inc |
---|
0,0 → 1,240 |
; 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 } |
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 \} } |
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 \\\} \\} \} } |
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 \\} \} } |
enable@substruct |
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 \} } |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/config.inc |
---|
0,0 → 1,0 |
__CPU_type fix p5 |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/debug-fdo.inc |
---|
0,0 → 1,422 |
; |
; 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 |
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: |
add esp,4*8+4 |
mov edx,..str |
sub esp,4*8+4 |
else |
mov edx,_str |
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 |
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 |
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 |
else if _hex in <ax,bx,cx,dx,si,di,bp,sp> |
if ~_hex eq ax |
movzx eax,_hex |
end if |
shl eax,16 |
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 |
shl eax,24 |
if (_num eq) |
mov edx,2 |
end if |
end if |
else if _hex eqtype 0 |
mov eax,_hex |
else |
add esp,4*8+4 |
mov eax,dword _hex |
sub esp,4*8+4 |
end if |
if ~_num eq |
mov edx,_num |
else |
mov edx,8 |
end if |
call fdo_debug_outhex |
popad |
popf |
} |
;----------------------------------------------------------------------------- |
debug_func fdo_debug_outchar |
debug_beginf |
pushad |
mov cl,al |
mov ebx,1 |
mov eax,63 |
mcall |
popad |
ret |
debug_endf |
debug_func fdo_debug_outstr |
debug_beginf |
mov eax,63 |
mov ebx,1 |
.l1: dec esi |
js .l2 |
mov cl,[edx] |
or cl,cl |
jz .l2 |
mcall |
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 |
@@: push 10 |
pop ecx |
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 __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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/applications/proc32.inc |
---|
0,0 → 1,270 |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ 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 } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ 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 } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ if parmbytes | localbytes |
push ebp |
mov ebp,esp |
if localbytes |
sub esp,localbytes |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
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 } |
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 \} |
virtual at ebp+8 |
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 =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $ - (ebp+8) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
macro locals |
\{ virtual at ebp-localbytes+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 = $-(ebp-localbytes) |
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-1) shr 2)+1) shl 2 |
end if \} } |
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 } |
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 |
match =label,def \{ ..tmp equ \} |
match tmp,..tmp \{ ..var def val \} |
match ,..tmp \{ label ..var val \} |
match =?, val \{ ..tmp equ \} |
match any =dup (=?), val \{ ..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 \} } |
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 } |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/data32.inc |
---|
0,0 → 1,504 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 db '¨æ¨ «¨§ æ¨ï IRQ',0 |
boot_picinit db '¨æ¨ «¨§ æ¨ï PIC',0 |
boot_v86machine db '¨æ¨ «¨§ æ¨ï á¨á⥬ë V86 ¬ è¨ë',0 |
boot_inittimer db '¨æ¨ «¨§ æ¨ï á¨á⥬®£® â ©¬¥à (IRQ0)',0 |
boot_initapic db '®¯ë⪠¨¨æ¨ «¨§ 樨 APIC',0 |
boot_enableirq db 'ª«îç¨âì ¯à¥àë¢ ¨ï 2, 6, 13, 14, 15',0 |
boot_enablint_ide db ' §à¥è¥¨¥ ¯à¥àë¢ ¨© ¢ ª®â஫«¥à¥ IDE',0 |
boot_detectfloppy db '®¨áª floppy ¤¨áª®¢®¤®¢',0 |
boot_detecthdcd db '®¨áª ¦¥áâª¨å ¤¨áª®¢ ¨ ATAPI ¯à¨¢®¤®¢',0 |
boot_getcache db '®«ã票¥ ¯ ¬ï⨠¤«ï ªíè ',0 |
boot_detectpart db '®¨áª à §¤¥«®¢ ¤¨áª®¢ëå ãáâனá⢠å',0 |
boot_init_sys db '¨æ¨ «¨§ æ¨ï á¨á⥬®£® ª â «®£ /sys',0 |
boot_loadlibs db ' £à㧪 ¡¨¡«¨®â¥ª (.obj)',0 |
boot_memdetect db '®«¨ç¥á⢮ ®¯¥à ⨢®© ¯ ¬ïâ¨',' ',' ¡',0 |
boot_tss db 'áâ ®¢ª TSSs',0 |
boot_cpuid db '⥨¥ CPUIDs',0 |
; boot_devices db '®¨áª ãáâனáâ¢',0 |
boot_timer db 'áâ ®¢ª â ©¬¥à ',0 |
boot_irqs db '¥à¥®¯à¥¤¥«¥¨¥ IRQ',0 |
boot_setmouse db 'áâ ®¢ª ¬ëè¨',0 |
boot_windefs db 'áâ ®¢ª áâ஥ª ®ª® ¯® 㬮«ç ¨î',0 |
boot_bgr db 'áâ ®¢ª ä® ',0 |
boot_resirqports db '¥§¥à¢¨à®¢ ¨¥ IRQ ¨ ¯®à⮢',0 |
boot_setrports db 'áâ ®¢ª ¤à¥á®¢ IRQ',0 |
boot_setostask db '®§¤ ¨¥ ¯à®æ¥áá ï¤à ',0 |
boot_allirqs db 'âªàë⨥ ¢á¥å IRQ',0 |
boot_tsc db '⥨¥ TSC',0 |
boot_cpufreq db ' áâ®â ¯à®æ¥áá®à ',' ',' æ',0 |
boot_pal_ega db 'áâ ®¢ª EGA/CGA 320x200 ¯ «¨âàë',0 |
boot_pal_vga db 'áâ ®¢ª VGA 640x480 ¯ «¨âàë',0 |
boot_failed db ' £à㧪 ¯¥à¢®£® ¯à¨«®¦¥¨ï ¥ 㤠« áì',0 |
boot_mtrr db 'áâ ®¢ª MTRR',0 |
boot_APIC_found db 'APIC ¢ª«îç¥', 0 |
boot_APIC_nfound db 'APIC ¥ ©¤¥', 0 |
if preboot_blogesc |
boot_tasking db 'ᥠ£®â®¢® ¤«ï § ¯ã᪠, ¦¬¨âॠESC ¤«ï áâ àâ ',0 |
end if |
else if lang eq sp |
include 'data32sp.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_initapic db 'Try to initialize APIC',0 |
boot_enableirq db 'Enable interrupts 2, 6, 13, 14, 15',0 |
boot_enablint_ide db 'Enable interrupts in IDE controller',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 |
intel_str db "GenuineIntel",0 |
AMD_str db "AuthenticAMD",0 |
szHwMouse db 'ATI2D',0 |
szPS2MDriver db 'PS2MOUSE',0 |
;szCOM_MDriver db 'COM_MOUSE',0 |
szUSB db 'USB',0 |
szAtiHW db '/rd/1/drivers/ati2d.drv',0 |
szSTART db 'START',0 |
szEXPORTS db 'EXPORTS',0 |
sz_EXPORTS db '_EXPORTS',0 |
szIMPORTS db 'IMPORTS',0 |
read_firstapp db '/sys/' |
firstapp db 'LAUNCHER',0 |
notifyapp db '@notify',0 |
if lang eq ru |
ud_user_message db '訡ª : ¥¯®¤¤¥à¦¨¢ ¥¬ ï ¨áâàãªæ¨ï ¯à®æ¥áá®à ',0 |
else if ~ lang eq sp |
ud_user_message db 'Error: unsupported processor instruction',0 |
end if |
bootpath db '/KOLIBRI ' |
bootpath2 db 0 |
vmode db '/sys/drivers/VMODE.MDR',0 |
;vrr_m db 'VRR_M',0 |
kernel_file db 'KERNEL MNT' |
dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0 |
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 |
syslang dd 1 |
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 |
endofcode: |
gdte: |
align 16 |
cur_saved_data: |
rb 4096 |
fpu_data: |
rb 512 |
mem_block_list rd 64*2 |
mem_used_list rd 64*2 |
mem_hash_cnt rd 64 |
heap_mutex MUTEX |
heap_size rd 1 |
heap_free rd 1 |
heap_blocks rd 1 |
free_blocks rd 1 |
mem_block_mask rd 2 |
next_memblock rd 1 |
mst MEM_STATE |
page_start rd 1 |
page_end rd 1 |
sys_page_map rd 1 |
os_stack_seg rd 1 |
srv.fd rd 1 |
srv.bk rd 1 |
align 16 |
_display display_t |
_WinMapAddress rd 1 |
_WinMapSize rd 1 |
def_cursor rd 1 |
def_cursor_clock rd 1 |
current_cursor rd 1 |
hw_cursor rd 1 |
cur_saved_base rd 1 |
cur.lock rd 1 ;1 - lock update, 2- hide |
cur.left rd 1 ;cursor clip box |
cur.top rd 1 |
cur.right rd 1 |
cur.bottom rd 1 |
cur.w rd 1 |
cur.h rd 1 |
ipc_tmp rd 1 |
ipc_pdir rd 1 |
ipc_ptab rd 1 |
proc_mem_map rd 1 |
proc_mem_pdir rd 1 |
proc_mem_tab rd 1 |
tmp_task_pdir rd 1 |
tmp_task_ptab rd 1 |
default_io_map rd 1 |
LFBSize rd 1 |
stall_mcs rd 1 |
current_slot rd 1 |
; status |
hd1_status rd 1 ; 0 - free : other - pid |
application_table_status rd 1 ; 0 - free : other - pid |
; device addresses |
mididp rd 1 |
midisp rd 1 |
cdbase rd 1 |
cdid rd 1 |
hdbase rd 1 ; for boot 0x1f0 |
hdid rd 1 |
hdpos rd 1 ; for boot 0x1 |
label known_part dword |
fat32part rd 1 ; for boot 0x1 |
cdpos rd 1 |
;CPUID information |
cpu_vendor rd 3 |
cpu_sign rd 1 |
cpu_info rd 1 |
cpu_caps rd 4 |
pg_data PG_DATA |
heap_test rd 1 |
buttontype rd 1 |
windowtypechanged rd 1 |
hd_entries rd 1 ;unused ? 0xfe10 |
mouse_active rd 1 |
mouse_pause rd 1 |
redrawmouse_unconditional rd 1 |
img_background rd 1 |
mem_BACKGROUND rd 1 |
static_background_data rd 1 |
cache_ide0: |
cache_ide0_pointer rd 1 |
cache_ide0_size rd 1 ; not use |
cache_ide0_data_pointer rd 1 |
cache_ide0_system_data_size rd 1 ; not use |
cache_ide0_appl_data_size rd 1 ; not use |
cache_ide0_system_data rd 1 |
cache_ide0_appl_data rd 1 |
cache_ide0_system_sad_size rd 1 |
cache_ide0_appl_sad_size rd 1 |
cache_ide0_search_start rd 1 |
cache_ide0_appl_search_start rd 1 |
cache_ide1: |
cache_ide1_pointer rd 1 |
cache_ide1_size rd 1 ; not use |
cache_ide1_data_pointer rd 1 |
cache_ide1_system_data_size rd 1 ; not use |
cache_ide1_appl_data_size rd 1 ; not use |
cache_ide1_system_data rd 1 |
cache_ide1_appl_data rd 1 |
cache_ide1_system_sad_size rd 1 |
cache_ide1_appl_sad_size rd 1 |
cache_ide1_search_start rd 1 |
cache_ide1_appl_search_start rd 1 |
cache_ide2: |
cache_ide2_pointer rd 1 |
cache_ide2_size rd 1 ; not use |
cache_ide2_data_pointer rd 1 |
cache_ide2_system_data_size rd 1 ; not use |
cache_ide2_appl_data_size rd 1 ; not use |
cache_ide2_system_data rd 1 |
cache_ide2_appl_data rd 1 |
cache_ide2_system_sad_size rd 1 |
cache_ide2_appl_sad_size rd 1 |
cache_ide2_search_start rd 1 |
cache_ide2_appl_search_start rd 1 |
cache_ide3: |
cache_ide3_pointer rd 1 |
cache_ide3_size rd 1 ; not use |
cache_ide3_data_pointer rd 1 |
cache_ide3_system_data_size rd 1 ; not use |
cache_ide3_appl_data_size rd 1 ; not use |
cache_ide3_system_data rd 1 |
cache_ide3_appl_data rd 1 |
cache_ide3_system_sad_size rd 1 |
cache_ide3_appl_sad_size rd 1 |
cache_ide3_search_start rd 1 |
cache_ide3_appl_search_start rd 1 |
debug_step_pointer rd 1 |
hdd_appl_data rb 1 ; 0 = system cache, 1 - application cache |
cd_appl_data rb 1 ; 0 = system cache, 1 - application cache |
lba_read_enabled rd 1 ; 0 = disabled , 1 = enabled |
pci_access_enabled rd 1 ; 0 = disabled , 1 = enabled |
timer_ticks_enable rb 1 ; for cd driver |
NumBiosDisks rd 1 |
BiosDisksData rb 200h |
BiosDiskCaches rb 80h*(cache_ide1-cache_ide0) |
BiosDiskPartitions rd 80h |
tetten: |
IncludeUGlobals |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui/event.inc |
---|
0,0 → 1,615 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 ; "âèðòóàëüíûé" event, èñïîëüçóþòñÿ òîëüêî ïîëÿ: |
; FreeEvents.fd=event_start è 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 - previos event below |
mov ecx, EV_SPACE ; current - in allocated space |
mov ebx, FreeEvents ; previos - íà÷àëî ñïèñêà |
push ebx ; îíî æå è êîíåö ïîòîì áóäåò |
;-------------------------------------- |
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 ; âîò îíî êîíöîì è ñòàëî |
mov [ebx+EVENT.fd], eax |
mov [eax+EVENT.bk], ebx |
;-------------------------------------- |
align 4 |
.fail: |
ret |
;----------------------------------------------------------------------------- |
EVENT_WATCHED equ 0x10000000 ;áèò 28 |
EVENT_SIGNALED equ 0x20000000 ;áèò 29 |
MANUAL_RESET equ 0x40000000 ;áèò 30 |
MANUAL_DESTROY equ 0x80000000 ;áèò 31 |
;----------------------------------------------------------------------------- |
align 4 |
create_event: ;; EXPORT use |
;info: |
; Ïåðåíîñèì EVENT èç ñïèñêà FreeEvents â ñïèñîê ObjList òåêóùåãî ñëîòà |
; EVENT.state óñòàíàâëèâàåì èç ecx, EVENT.code êîñâåííî èç esi (åñëè 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: |
; Áåðåì íîâûé event èç FreeEvents, çàïîëíÿåì åãî ïîëÿ, êàê óêàçàíî â ecx,edx,esi |
; è óñòàíàâëèâàåì â ñïèñîê, óêàçàííûé â ebx. |
; Âîçâðàùàåì ñàì event (â eax), è åãî uid (â 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 [eax+EVENT.id],edx,[event_uid] |
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 - óêàçàòåëü íà event, ÊÎÒÎÐÛÉ âñòàâëÿåì |
; ebx - óêàçàòåëü íà event, ÏÎÑËÅ êîòîðîãî âñòàâëÿåì |
;scratched: ebx,ecx |
mov ecx, eax ; ecx=eax=Self, ebx=NewLeft |
xchg ecx, [ebx+EVENT.fd] ; NewLeft.fd=Self, ecx=NewRight |
cmp eax, ecx ; ñòîï, ñåáå äóìàþ... |
je .break ; - à íå äóðàê ëè ÿ? |
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: ; êðèâî êàê-òî... |
pop edi |
pushfd |
cli |
call pid_to_slot ; saved all registers (eax - retval) |
shl eax, 8 |
jz RemoveEventTo.break ; POPF+RET |
jmp edi ; øòàòíûé âîçâðàò |
;----------------------------------------------------------------------------- |
align 4 |
raise_event: ;; EXPORT use |
;info: |
; Óñòàíàâëèâàåì äàííûå EVENT.code |
; Åñëè òàì ôëàã EVENT_SIGNALED óæå àêòèâåí - áîëüøå íè÷åãî |
; Èíà÷å: ýòîò ôëàã âçâîäèòñÿ, çà èñêëþ÷åíèåì ñëó÷àÿ íàëè÷èÿ ôëàãà EVENT_WATCHED â edx |
;  ýòîì ñëó÷àå EVENT_SIGNALED âçâîäèòñÿ ëèøü ïðè íàëè÷èå EVENT_WATCHED â ñàìîì ñîáûòèè |
;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: |
; Ñîçäàåò íîâûé EVENT (âûòàñêèâàåò èç ñïèñêà FreeEvents) â ñïèñêå EventList |
; öåëåâîãî ñëîòà (eax=pid), ñ äàííûìè èç esi êîñâåííî, è 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: |
; Îæèäàíèå "àáñòðàêòíîãî" ñîáûòèÿ ÷åðåç ïåðåâîä ñëîòà â 5-þ ïîçèöèþ. |
; Àáñòðàêòíîñòü çàêëþ÷åíà â òîì, ÷òî ôàêò ñîáûòèÿ îïðåäåëÿåòñÿ ôóíêöèåé APPDATA.wait_test, |
; êîòîðàÿ çàäàåòñÿ êëèåíòîì è ìîæåò áûòü ôàêòè÷åñêè ëþáîé. |
; Ýòî ïîçâîëÿåò shed-ó íàäåæíî îïðåäåëèòü ôàêò ñîáûòèÿ, è íå ñîâåðøàòü "õîëîñòûõ" ïåðåêëþ÷åíèé, |
; ïðåäíàçíà÷åííûõ äëÿ ðàçáîðîê òèïà "ñâîé/÷óæîé" âíóòðè çàäà÷è. |
;param: |
; edx - wait_test, êëèåíòñêàÿ ô-ÿ òåñòèðîâàíèÿ (àäðåñ êîäà) |
; ecx - wait_param, äîïîëíèòåëüíûé ïàðàìåòð, âîçìîæíî íåîáõîäèìûé äëÿ [wait_test] |
; ebx - wait_timeout |
;retval: |
; eax - ðåçóëüòàò âûçîâà [wait_test] (=0 => timeout) |
;scratched: esi |
mov esi, [current_slot] |
mov [esi+APPDATA.wait_param], ecx |
pushad |
mov ebx, esi;ïîêà ýòî âîïðîñ, ÷åãî êóäû ñóâàòü.......... |
pushfd ; ýòî ñëåäñòâèå îáùåé êîíöåïöèè: ïóñòü ô-ÿ òåñòèðîâàíèÿ èìååò |
cli ; ïðàâî ðàññ÷èòûâàòü íà çàêðûòûå ïðåðûâàíèÿ, êàê ïðè âûçîâå èç 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 [esi+APPDATA.wait_begin],eax,[timer_ticks] |
mov eax, [TASK_BASE] |
mov [eax+TASKDATA.state], 5 |
call change_task |
mov eax, [esi+APPDATA.wait_param] |
;-------------------------------------- |
align 4 |
@@: |
ret |
;----------------------------------------------------------------------------- |
align 4 |
wait_event: ;; EXPORT use |
;info: |
; Îæèäàíèå ôëàãà EVENT_SIGNALED â ñîâåðøåííî êîíêðåòíîì Event |
; (óñòàíàâëèâàåìîãî, íàäî ïîëàãàòü, ÷åðåç raise_event) |
; Ïðè àêòèâíîì ôëàãå MANUAL_RESET - áîëüøå íè÷åãî |
; Èíà÷å: ôëàãè EVENT_SIGNALED è EVENT_WATCHED ó ïîëó÷åííîãî ñîáûòèÿ ñáðàñûâàþòñÿ, |
; è, ïðè àêòèâíîì MANUAL_DESTROY - ïåðåìåùàåòñÿ â ñïèñîê ObjList òåêóùåãî ñëîòà, |
; à ïðè íå àêòèâíîì - óíè÷òîæàåòñÿ øòàòíî (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: |
; Îæèäàíèå ëþáîãî ñîáûòèÿ â î÷åðåäè EventList òåêóùåãî ñëîòà |
; Äàííûå ñîáûòèÿ code - êîïèðóþòñÿ â ïàìÿòü ïðèëîæåíèÿ (êîñâåííî ïî edi) |
; Ïðè àêòèâíîì ôëàãå MANUAL_RESET - áîëüøå íè÷åãî |
; Èíà÷å: ôëàãè EVENT_SIGNALED è EVENT_WATCHED ó ïîëó÷åííîãî ñîáûòèÿ ñáðàñûâàþòñÿ, |
; è, ïðè àêòèâíîì MANUAL_DESTROY - ïåðåìåùàåòñÿ â ñïèñîê ObjList òåêóùåãî ñëîòà, |
; à ïðè íå àêòèâíîì - óíè÷òîæàåòñÿ øòàòíî (destroy_event.internal) |
;param: |
; edi - àäðåñ â êîäå ïðèëîæåíèÿ äëÿ êîïèðîâàíèÿ äàííûõ èç EVENT.code |
;retval: |
; eax - ñîáñòâåííî EVENT (áóäåì íàçûâàòü ýòî åãî õýíäëîì) |
;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: |
; Ïåðåíîñèì EVENT â ñïèñîê FreeEvents, ÷èñòèì ïîëÿ magic,destroy,pid,id |
;param: |
; eax - event |
; ebx - uid (for Dummy testing) |
;retval: |
; eax - àäðåñ îáúåêòà EVENT (=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: |
; êëèåíòñêàÿ ô-ÿ òåñòèðîâàíèÿ äëÿ get_event_ex |
;warning: |
; -don't use [TASK_BASE],[current_slot],[CURRENT_TASK] - it is not for your slot |
; -may be assumed, that interrupt are disabled |
; -it is not restriction for scratched registers |
;param: |
; ebx - àäðåñ APPDATA ñëîòà òåñòèðîâàíèÿ |
;retval: |
; eax - àäðåñ îáúåêòà EVENT (=0 => fail) |
add ebx, APP_EV_OFFSET |
mov eax, [ebx+APPOBJ.bk] ; âûáèðàåì ñ êîíöà, ïî ïðèíöèïó FIFO |
cmp eax, ebx ; empty ??? |
je get_event_alone.ret0 |
;-------------------------------------- |
align 4 |
.ret: |
ret |
;----------------------------------------------------------------------------- |
align 4 |
get_event_alone: |
;info: |
; êëèåíòñêàÿ ô-ÿ òåñòèðîâàíèÿ äëÿ wait_event |
;warning: |
; -don't use [TASK_BASE],[current_slot],[CURRENT_TASK] - it is not for your slot |
; -may be assumed, that interrupt are disabled |
; -it is not restriction for scratched registers |
;param: |
; ebx - àäðåñ APPDATA ñëîòà òåñòèðîâàíèÿ |
;retval: |
; eax - àäðåñ îáúåêòà EVENT (=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_COUNT+1+eax], dl |
;-------------------------------------- |
align 4 |
.result: |
setae byte[esp+32] ;ñ÷èòàåì, ÷òî èñõîäíî: dword[esp+32]==72 |
;-------------------------------------- |
align 4 |
.retf: |
popfd |
;-------------------------------------- |
align 4 |
.ret: |
ret |
;----------------------------------------------------------------------------- |
align 4 |
sys_getevent: ;; f11 |
mov ebx, [current_slot];ïîêà ýòî âîïðîñ, ÷åãî êóäû ñóâàòü.......... |
pushfd ; ýòî ñëåäñòâèå îáùåé êîíöåïöèè: ïóñòü ô-ÿ òåñòèðîâàíèÿ èìååò |
cli ; ïðàâî ðàññ÷èòûâàòü íà çàêðûòûå ïðåðûâàíèÿ, êàê ïðè âûçîâå èç 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: |
; êëèåíòñêàÿ ô-ÿ òåñòèðîâàíèÿ äëÿ ïðèëîæåíèé (f10,f23) |
;warning: |
; -don't use [TASK_BASE],[current_slot],[CURRENT_TASK] - it is not for your slot |
; -may be assumed, that interrupt are disabled |
; -it is not restriction for scratched registers |
;param: |
; ebx - àäðåñ APPDATA ñëîòà òåñòèðîâàíèÿ |
;retval: |
; eax - íîìåð ñîáûòèÿ (=0 => no events) |
movzx edi, bh ; bh is assumed as [CURRENT_TASK] |
shl edi, 5 |
add edi, CURRENT_TASK ; edi is assumed as [TASK_BASE] |
mov ecx, [edi+TASKDATA.event_mask] |
and ecx, 0x7FFFFFFF |
;-------------------------------------- |
align 4 |
.loop: ; ïîêà íå èñ÷åðïàåì âñå áèòû ìàñêè |
bsr eax, ecx ; íàõîäèì íåíóëåâîé áèò ìàñêè (31 -> 0) |
jz .no_events ; èñ÷åðïàëè âñå áèòû ìàñêè, íî íè÷åãî íå íàøëè ??? |
btr ecx, eax ; ñáðàñûâàåì ïðîâåðÿåìûé áèò ìàñêè |
; ïåðåõîäèì íà îáðàáîò÷èê ýòîãî (eax) áèòà |
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.event_mask], 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, [TASK_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 |
dec byte[BTN_COUNT] |
jmp .loop |
;-------------------------------------- |
align 4 |
.Keys: ; eax==1 |
cmp edx, [TASK_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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui/font.inc |
---|
0,0 → 1,239 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;------------------------------------------------------------------------------ |
align 4 |
dtext_asciiz_esi: ; for skins title out |
push eax |
xor eax, eax |
inc eax |
jmp dtext.1 |
;------------------------------------------------------------------------------ |
align 4 |
dtext: |
; ebx x & y |
; ecx style ( 0xX0000000 ) & color ( 0x00RRGGBB ) |
; X = ABnnb: |
; nn = font |
; A = 0 <=> output esi characters; otherwise output ASCIIZ string |
; B = 1 <=> fill background with color eax |
; edx start of text |
; edi 1 force or user area for redirect |
push eax |
xor eax, eax |
;-------------------------------------- |
align 4 |
.1: |
pushad |
movsx eax, bx ; eax=y |
sar ebx, 16 ; ebx=x |
xchg eax, ebx ; eax=x, ebx=y |
cmp esi, 255 |
jb .loop |
mov esi, 255 |
;-------------------------------------- |
align 4 |
.loop: |
test ecx, ecx |
js .test_asciiz |
dec esi |
js .end |
jmp @f |
;-------------------------------------- |
align 4 |
.test_asciiz: |
cmp byte [edx], 0 |
jz .end |
cmp byte [esp+28], 1 |
jne @f |
dec esi |
js .end |
;-------------------------------------- |
align 4 |
@@: |
inc edx |
pushad |
movzx edx, byte [edx-1] |
test ecx, 0x10000000 |
jnz .font2 |
mov esi, 9 |
lea ebp, [FONT_I+8*edx+edx] |
;-------------------------------------- |
align 4 |
.symloop1: |
mov dl, byte [ebp] |
or dl, 1 shl 6 |
;-------------------------------------- |
align 4 |
.pixloop1: |
shr dl, 1 |
jz .pixloop1end |
jnc .nopix |
test ecx, 0x08000000 ; redirect the output to the user area |
jz @f |
call draw_text_to_user_area |
jmp .pixloop1cont |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
; call [putpixel] |
call __sys_putpixel |
jmp .pixloop1cont |
;-------------------------------------- |
align 4 |
.nopix: |
test ecx, 0x40000000 |
jz .pixloop1cont |
push ecx |
mov ecx, [esp+4+20h+20h] |
test ecx, 0x08000000 ; redirect the output to the user area |
jz @f |
call draw_text_to_user_area |
pop ecx |
jmp .pixloop1cont |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
; call [putpixel] |
call __sys_putpixel |
pop ecx |
;-------------------------------------- |
align 4 |
.pixloop1cont: |
inc eax |
jmp .pixloop1 |
;-------------------------------------- |
align 4 |
.pixloop1end: |
sub eax, 6 |
inc ebx |
inc ebp |
dec esi |
jnz .symloop1 |
popad |
add eax, 6 |
jmp .loop |
;-------------------------------------- |
align 4 |
.font2: |
add edx, edx |
lea ebp, [FONT_II+4*edx+edx+1] |
push 9 |
movzx esi, byte [ebp-1] |
;-------------------------------------- |
align 4 |
.symloop2: |
mov dl, byte [ebp] |
push esi |
;-------------------------------------- |
align 4 |
.pixloop2: |
shr dl, 1 |
jnc .nopix2 |
test ecx, 0x08000000 ; redirect the output to the user area |
jz @f |
call draw_text_to_user_area |
jmp .pixloop2cont |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
; call [putpixel] |
call __sys_putpixel |
jmp .pixloop2cont |
;-------------------------------------- |
align 4 |
.nopix2: |
test ecx, 0x40000000 |
jz .pixloop2cont |
push ecx |
mov ecx, [esp+12+20h+20h] |
test ecx, 0x08000000 ; redirect the output to the user area |
jz @f |
call draw_text_to_user_area |
pop ecx |
jmp .pixloop2cont |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
; call [putpixel] |
call __sys_putpixel |
pop ecx |
;-------------------------------------- |
align 4 |
.pixloop2cont: |
inc eax |
dec esi |
jnz .pixloop2 |
pop esi |
sub eax, esi |
inc ebx |
inc ebp |
dec dword [esp] |
jnz .symloop2 |
pop eax |
add dword [esp+28], esi |
popad |
jmp .loop |
;-------------------------------------- |
align 4 |
.end: |
popad |
pop eax |
ret |
;------------------------------------------------------------------------------ |
; eax = x coordinate |
; ebx = y coordinate |
; ecx = ?? RR GG BB |
; edi = user area |
align 4 |
draw_text_to_user_area: |
pushad |
imul ebx, [edi+0] |
add eax, ebx |
shl eax, 2 |
add eax, edi |
add eax, 8 |
and ecx, 0xffffff |
or ecx, 0xff000000 ; not transparent |
mov [eax], ecx ; store pixel |
popad |
ret |
;------------------------------------------------------------------------------ |
align 4 |
FONT_I: |
file 'char.mt' |
;------------------------------------------------------------------------------ |
align 4 |
FONT_II: |
file 'char2.mt' |
;------------------------------------------------------------------------------ |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui/mouse.inc |
---|
0,0 → 1,718 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2012. 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 and call |
;? appropriate handlers |
;------------------------------------------------------------------------------ |
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 |
; NOTE: this code wouldn't be necessary if we knew window did |
; already redraw itself after call above |
or eax, eax |
jz @f |
and [mouse.state.buttons], 0 |
jmp .exit |
; 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're 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 |
align 4 |
;------------------------------------------------------------------------------ |
mouse._.left_button_press_handler: ;/////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Called when left mouse button has been pressed down |
;------------------------------------------------------------------------------ |
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 |
mov eax, [timer_ticks] |
mov ebx, eax |
xchg ebx, [mouse.active_sys_window.last_ticks] |
sub eax, ebx |
cmp eax, 50 |
jg @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: |
; mov eax, mouse.active_sys_window.old_box |
; call sys_window_start_moving_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 |
;------------------------------------------------------------------------------ |
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 |
ret |
align 4 |
;------------------------------------------------------------------------------ |
mouse._.right_button_press_handler: ;////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Called when right mouse button has been pressed down |
;------------------------------------------------------------------------------ |
test [mouse.state.buttons], not mouse.RIGHT_BUTTON_FLAG |
jnz .exit |
call mouse._.find_sys_window_under_cursor |
call mouse._.check_sys_window_actions |
test al, mouse.WINDOW_MOVE_FLAG |
jz .exit |
call sys_window_rollup_handler |
.exit: |
ret |
align 4 |
;------------------------------------------------------------------------------ |
mouse._.right_button_release_handler: ;//////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Called when right mouse button has been released |
;------------------------------------------------------------------------------ |
ret |
align 4 |
;------------------------------------------------------------------------------ |
mouse._.middle_button_press_handler: ;///////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Called when middle mouse button has been pressed down |
;------------------------------------------------------------------------------ |
ret |
align 4 |
;------------------------------------------------------------------------------ |
mouse._.middle_button_release_handler: ;/////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Called when middle mouse button has been released |
;------------------------------------------------------------------------------ |
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, [Screen_Max_X] |
jl @f |
sub eax, [Screen_Max_X] |
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, [Screen_Max_Y] |
jle .call_window_handler |
sub eax, [Screen_Max_Y] |
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, [Screen_Max_Y] |
jle .check_resize_e |
sub eax, [Screen_Max_Y] |
neg eax |
add [mouse.active_sys_window.new_box.height], eax |
mov ecx, [Screen_Max_Y] |
cmp ecx, eax |
jge .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, [Screen_Max_X] |
jle .call_window_handler |
sub eax, [Screen_Max_X] |
neg eax |
add [mouse.active_sys_window.new_box.width], eax |
mov ecx, [Screen_Max_X] |
cmp ecx, eax |
jge .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 |
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, [Screen_Max_X] |
; inc esi |
; imul esi, [mouse.state.pos.y] |
mov esi, [mouse.state.pos.y] |
mov esi, [d_width_calc_area + esi*4] |
add esi, [_WinMapAddress] |
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: ;//////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
; 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: ;//////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
;< 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui/mousepointer.inc |
---|
0,0 → 1,250 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2288 $ |
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 |
/kernel/branches/net/gui/window.inc |
---|
0,0 → 1,2421 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
macro FuncTable name, table_name, [label] |
{ |
common |
align 4 |
\label name#.#table_name dword |
forward |
dd name#.#label |
common |
name#.sizeof.#table_name = $ - name#.#table_name |
} |
uglobal |
common_colours rd 32 |
draw_limits RECT |
endg |
align 4 |
;------------------------------------------------------------------------------ |
syscall_draw_window: ;///// system function 0 ///////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
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 |
;-------------------------------------- |
align 4 |
@@: |
dec al |
jnz @f |
; type II - only reserve area, no draw |
; call sys_window_mouse |
; call [draw_pointer] |
call __sys_draw_pointer |
jmp .exit |
;-------------------------------------- |
align 4 |
@@: |
dec al |
jnz @f |
; type III - new style |
call drawwindow_III |
jmp window._.draw_window_caption.2 |
; type IV & V - skinned window (resizable & not) |
;-------------------------------------- |
align 4 |
@@: |
mov eax, [TASK_COUNT] |
movzx eax, word[WIN_POS + eax * 2] |
cmp eax, [CURRENT_TASK] |
setz al |
movzx eax, al |
push eax |
call drawwindow_IV |
jmp window._.draw_window_caption.2 |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
;------------------------------------------------------------------------------ |
syscall_display_settings: ;///// system function 48 /////////////////////////// |
;------------------------------------------------------------------------------ |
;; Redraw screen: |
;< ebx = 0 |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Set button style: |
;< ebx = 1 |
;< ecx = 0 (flat) or 1 (with gradient) |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Set system color palette: |
;< ebx = 2 |
;< ecx = pointer to color table |
;< edx = size of color table |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Get system color palette: |
;< ebx = 3 |
;< ecx = pointer to color table buffer |
;< edx = size of color table buffer |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Get skinned caption height: |
;< ebx = 4 |
;> eax = height in pixels |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Get screen working area: |
;< ebx = 5 |
;> eax = pack[16(left), 16(right)] |
;> ebx = pack[16(top), 16(bottom)] |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Set screen working area: |
;< ebx = 6 |
;< ecx = pack[16(left), 16(right)] |
;< edx = pack[16(top), 16(bottom)] |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Get skin margins: |
;< ebx = 7 |
;> eax = pack[16(left), 16(right)] |
;> ebx = pack[16(top), 16(bottom)] |
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
;; Set skin: |
;< ebx = 8 |
;< ecx = pointer to FileInfoBlock struct |
;> eax = FS error code |
;------------------------------------------------------------------------------ |
cmp ebx, .sizeof.ftable / 4 |
ja @f |
jmp [.ftable + ebx * 4] |
;-------------------------------------- |
align 4 |
@@: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.00: |
xor eax, eax |
inc ebx |
cmp [windowtypechanged], ebx |
jne .exit |
mov [windowtypechanged], eax |
jmp syscall_display_settings._.redraw_whole_screen |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.01: |
and ecx, 1 |
cmp ecx, [buttontype] |
je .exit |
mov [buttontype], ecx |
mov [windowtypechanged], ebx |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.02: |
dec ebx |
mov esi, ecx |
and edx, 127 |
mov edi, common_colours |
mov ecx, edx |
rep movsb |
mov [windowtypechanged], ebx |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.03: |
mov edi, ecx |
and edx, 127 |
mov esi, common_colours |
mov ecx, edx |
rep movsb |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.04: |
mov eax, [_skinh] |
mov [esp + 32], eax |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.05: |
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 |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.06: |
xor esi, esi |
mov edi, [Screen_Max_X] |
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 |
;-------------------------------------- |
align 4 |
@@: |
mov [screen_workarea.left], eax |
cmp ebx, edi |
jle @f |
mov ebx, edi |
;-------------------------------------- |
align 4 |
@@: |
mov [screen_workarea.right], ebx |
;-------------------------------------- |
align 4 |
.check_horizontal: |
mov edi, [Screen_Max_Y] |
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 |
;-------------------------------------- |
align 4 |
@@: |
mov [screen_workarea.top], eax |
cmp ebx, edi |
jle @f |
mov ebx, edi |
;-------------------------------------- |
align 4 |
@@: |
mov [screen_workarea.bottom], ebx |
;-------------------------------------- |
align 4 |
.check_if_redraw_needed: |
or esi, esi |
jz .exit |
call repos_windows |
jmp syscall_display_settings._.calculate_whole_screen |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.07: |
mov eax, [_skinmargins + 0] |
mov [esp + 32], eax |
mov eax, [_skinmargins + 4] |
mov [esp + 20], eax |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings.08: |
mov ebx, ecx |
call read_skin_file |
mov [esp + 32], eax |
test eax, eax |
jnz .exit |
call syscall_display_settings._.calculate_whole_screen |
jmp syscall_display_settings._.redraw_whole_screen |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings._.calculate_whole_screen: |
xor eax, eax |
xor ebx, ebx |
mov ecx, [Screen_Max_X] |
mov edx, [Screen_Max_Y] |
jmp calculatescreen |
;------------------------------------------------------------------------------ |
align 4 |
syscall_display_settings._.redraw_whole_screen: |
xor eax, eax |
mov [draw_limits.left], eax |
mov [draw_limits.top], eax |
mov eax, [Screen_Max_X] |
mov [draw_limits.right], eax |
mov eax, [Screen_Max_Y] |
mov [draw_limits.bottom], eax |
mov eax, window_data |
jmp redrawscreen |
;------------------------------------------------------------------------------ |
align 4 |
;------------------------------------------------------------------------------ |
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_TASK] |
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] |
call window._.set_window_box |
add esp, sizeof.BOX |
; NOTE: do we really need this? to be reworked |
; mov byte[DONT_DRAW_MOUSE], 0 ; mouse pointer |
; mov byte[MOUSE_BACKGROUND], 0 ; no mouse under |
; mov byte[MOUSE_DOWN], 0 ; react to mouse up/down |
; NOTE: do we really need this? to be reworked |
; call [draw_pointer] |
;-------------------------------------- |
align 4 |
.exit: |
ret |
;------------------------------------------------------------------------------ |
align 4 |
;------------------------------------------------------------------------------ |
syscall_window_settings: ;///// system function 71 ///////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
dec ebx ; subfunction #1 - set window caption |
jnz .exit_fail |
; NOTE: only window owner thread can set its caption, |
; so there's no parameter for PID/TID |
mov edi, [CURRENT_TASK] |
shl edi, 5 |
mov [edi * 8 + SLOT_BASE + APPDATA.wnd_caption], ecx |
or [edi + window_data + WDATA.fl_wstyle], WSTYLE_HASCAPTION |
call window._.draw_window_caption |
xor eax, eax ; eax = 0 (success) |
ret |
; .get_window_caption: |
; dec eax ; subfunction #2 - get window caption |
; jnz .exit_fail |
; not implemented yet |
;-------------------------------------- |
align 4 |
.exit_fail: |
xor eax, eax |
inc eax ; eax = 1 (fail) |
ret |
;------------------------------------------------------------------------------ |
align 4 |
;------------------------------------------------------------------------------ |
set_window_defaults: ;///////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
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, [TASK_COUNT] |
cmp ebp, 1 |
jbe .exit |
push edx ecx ebx eax |
;-------------------------------------- |
align 4 |
.next_window: |
movzx edi, word[WIN_POS + esi * 2] |
shl edi, 5 |
cmp [CURRENT_TASK + edi + TASKDATA.state], TSTATE_FREE |
je .skip_window |
add edi, window_data |
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED |
jnz .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 |
pop eax ebx ecx edx |
;-------------------------------------- |
align 4 |
.exit: |
pop ebp |
inc [_display.mask_seqno] |
popfd |
pop esi |
ret |
;------------------------------------------------------------------------------ |
align 4 |
;------------------------------------------------------------------------------ |
repos_windows: ;/////////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
mov ecx, [TASK_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, [Screen_Max_X] |
cmp eax, ebx |
jle .fix_vertical |
mov eax, [edi + WDATA.box.width] |
sub eax, ebx |
jle @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, [Screen_Max_Y] |
cmp eax, ebx |
jle .fix_client_box |
mov eax, [edi + WDATA.box.height] |
sub eax, ebx |
jle @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 |
;------------------------------------------------------------------------------ |
;sys_window_mouse: ;//////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
; NOTE: commented out since doesn't provide necessary functionality |
; anyway, to be reworked |
; push eax |
; |
; mov eax, [timer_ticks] |
; cmp [new_window_starting], eax |
; jb .exit |
; |
; mov byte[MOUSE_BACKGROUND], 0 |
; mov byte[DONT_DRAW_MOUSE], 0 |
; |
; mov [new_window_starting], eax |
; |
; .exit: |
; pop eax |
; ret |
;------------------------------------------------------------------------------ |
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? |
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, 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, [TASK_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 |
mov byte[MOUSE_DOWN], 1 |
call window._.window_activate |
pushad |
mov edi, [TASK_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, [TASK_COUNT] |
movzx esi, word[WIN_POS + edi * 2] |
call window._.set_screen |
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 |
mov byte[MOUSE_BACKGROUND], al |
mov byte[DONT_DRAW_MOUSE], al |
;-------------------------------------- |
align 4 |
.exit: |
mov byte[MOUSE_DOWN], 0 |
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, [TASK_COUNT] |
;-------------------------------------- |
align 4 |
.loop: |
movzx edi, word[WIN_POS + eax * 2] |
shl edi, 5 |
; it is a unused slot? |
cmp dword [edi+CURRENT_TASK+TASKDATA.state], 9 |
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._.calculate_whole_screen |
call syscall_display_settings._.redraw_whole_screen |
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, [TASK_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 |
inc [_display.mask_seqno] |
mov byte[MOUSE_BACKGROUND], 0 |
;-------------------------------------- |
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, [TASK_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 |
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 |
FuncTable syscall_display_settings, ftable, \ |
00, 01, 02, 03, 04, 05, 06, 07, 08 |
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 |
;uglobal |
; NOTE: commented out since doesn't provide necessary functionality anyway, |
; to be reworked |
; new_window_starting dd ? |
;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] |
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] |
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_TASK] |
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 |
or [edi + WDATA.fl_wdrawn], 1 |
; 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! He is terrible in rage - usually he throws stones! |
mov [redrawmouse_unconditional], 1 |
; NOTE: commented out since doesn't provide necessary functionality |
; anyway, to be reworked |
; mov eax, [timer_ticks] ; [0xfdf0] |
; add eax, 100 |
; mov [new_window_starting], eax |
; no it wasn't, 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_TASK] |
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, [Screen_Max_X] |
cmp ecx, esi |
ja .fix_width_high |
;-------------------------------------- |
align 4 |
.check_left: |
or eax, eax |
jl .fix_left_low |
add eax, ecx |
cmp eax, esi |
jg .fix_left_high |
;-------------------------------------- |
align 4 |
.check_height: |
mov esi, [Screen_Max_Y] |
cmp edx, esi |
ja .fix_height_high |
;-------------------------------------- |
align 4 |
.check_top: |
or ebx, ebx |
jl .fix_top_low |
add ebx, edx |
cmp ebx, esi |
jg .fix_top_high |
;-------------------------------------- |
align 4 |
.exit: |
pop esi edx ecx ebx eax |
ret |
;-------------------------------------- |
align 4 |
.fix_width_high: |
mov ecx, esi |
mov [edi + WDATA.box.width], esi |
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 |
mov [edi + WDATA.box.left], eax |
jmp .check_height |
;-------------------------------------- |
align 4 |
.fix_height_high: |
mov edx, esi |
mov [edi + WDATA.box.height], esi |
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 |
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 edi, [Screen_Max_X] |
; inc edi |
; mov esi, edi |
mov esi, [Screen_Max_X] |
inc esi |
; imul edi, ebx |
mov edi, [d_width_calc_area + ebx*4] |
add edi, eax |
add edi, [_WinMapAddress] |
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, [Screen_Max_X] ; screen_sx |
; inc eax |
; imul eax, ebx |
mov eax, [d_width_calc_area + ebx*4] |
add eax, [esp] |
add eax, [_WinMapAddress] |
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, [Screen_Max_X] ; screen.x |
inc ebp |
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, [TASK_COUNT] |
; DEBUGF 1, "K : TASK_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: |
; ax <- process no |
movzx ebx, word[esi] |
; ax <- position in window stack |
movzx ebx, word[WIN_STACK + ebx * 2] |
; drop others |
xor eax, eax |
;-------------------------------------- |
align 4 |
.next_stack_window: |
cmp eax, [TASK_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 processes |
mov ax, [TASK_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, [TASK_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, [TASK_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, [TASK_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, [TASK_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 |
cmp [CURRENT_TASK + 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, [TASK_COUNT] |
movzx edx, word[WIN_POS + edx * 2] |
cmp edx, [CURRENT_TASK] |
jne @f |
inc eax |
;-------------------------------------- |
align 4 |
@@: |
mov edx, [CURRENT_TASK] |
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_TASK] |
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 |
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: |
mov ebp, [edi + window_data + WDATA.box.left - 2] |
mov bp, word[edi + window_data + WDATA.box.top] |
movzx eax, word[edi + window_data + WDATA.box.width] |
sub ax, [_skinmargins.left] |
sub ax, [_skinmargins.right] |
push edx |
cwde |
cdq |
mov ebx, 6 |
idiv ebx |
pop edx |
or eax, eax |
js .exit |
mov esi, eax |
mov ebx, dword[_skinmargins.left - 2] |
mov bx, word[_skinh] |
sub bx, [_skinmargins.bottom] |
sub bx, [_skinmargins.top] |
sar bx, 1 |
adc bx, 0 |
add bx, [_skinmargins.top] |
add bx, -3 |
add ebx, ebp |
jmp .dodraw |
;-------------------------------------- |
align 4 |
.not_skinned: |
cmp al, 1 |
je .exit |
mov ebp, [edi + window_data + WDATA.box.left - 2] |
mov bp, word[edi + window_data + WDATA.box.top] |
movzx eax, word[edi + window_data + WDATA.box.width] |
sub eax, 16 |
push edx |
cwde |
cdq |
mov ebx, 6 |
idiv ebx |
pop edx |
or eax, eax |
js .exit |
mov esi, eax |
mov ebx, 0x00080007 |
add ebx, ebp |
;-------------------------------------- |
align 4 |
.dodraw: |
mov ecx, [common_colours + 16] |
or ecx, 0x80000000 |
xor edi, edi |
call dtext_asciiz_esi |
;-------------------------------------- |
align 4 |
.exit: |
; call [draw_pointer] |
call __sys_draw_pointer |
ret |
;------------------------------------------------------------------------------ |
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 |
;------------------------------------------------------------------------------ |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/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/net/gui/char2.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/net/gui/button.inc |
---|
0,0 → 1,508 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;============================================================================== |
;///// public functions /////////////////////////////////////////////////////// |
;============================================================================== |
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 |
align 4 |
;------------------------------------------------------------------------------ |
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 |
push ebx ecx edx |
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, [CURRENT_TASK] |
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 |
pop edx ecx ebx |
; do we also need to draw the button? |
test edx, 0x40000000 |
jnz .exit |
; draw button body |
pushad |
; calculate window-relative coordinates |
movzx edi, cx |
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 |
shl eax, 16 |
mov ax, bx |
add ax, word[esp + 16] |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
; calculate initial color |
mov ecx, esi |
cmp [buttontype], 0 |
je @f |
call button._.incecx2 |
; set button height counter |
@@: |
mov edx, edi |
.next_line: |
call button._.button_dececx |
push edi |
xor edi, edi |
; call [draw_line] |
call __sys_draw_line |
pop edi |
add ebx, 0x00010001 |
dec edx |
jnz .next_line |
popad |
; draw button frame |
push ebx ecx |
; calculate window-relative coordinates |
shr ebx, 16 |
shr ecx, 16 |
mov eax, [TASK_BASE] |
add ebx, [eax - twdw + WDATA.box.left] |
add ecx, [eax - twdw + WDATA.box.top] |
; top border |
mov eax, ebx |
shl eax, 16 |
mov ax, bx |
add ax, [esp + 4] |
mov ebx, ecx |
shl ebx, 16 |
mov bx, cx |
push ebx |
xor edi, edi |
mov ecx, esi |
call button._.incecx |
; call [draw_line] |
call __sys_draw_line |
; bottom border |
movzx edx, word[esp + 4 + 0] |
add ebx, edx |
shl edx, 16 |
add ebx, edx |
mov ecx, esi |
call button._.dececx |
; call [draw_line] |
call __sys_draw_line |
; left border |
pop ebx |
push edx |
mov edx, eax |
shr edx, 16 |
mov ax, dx |
mov edx, ebx |
shr edx, 16 |
mov bx, dx |
add bx, [esp + 4 + 0] |
pop edx |
mov ecx, esi |
call button._.incecx |
; call [draw_line] |
call __sys_draw_line |
; right border |
mov dx, [esp + 4] |
add ax, dx |
shl edx, 16 |
add eax, edx |
add ebx, 0x00010000 |
mov ecx, esi |
call button._.dececx |
; call [draw_line] |
call __sys_draw_line |
pop ecx ebx |
.exit: |
ret |
; FIXME: mutex needed |
syscall_button.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, [CURRENT_TASK] |
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 |
.exit: |
ret |
align 4 |
;------------------------------------------------------------------------------ |
sys_button_activate_handler: ;///////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
;> 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 |
;------------------------------------------------------------------------------ |
call button._.find_button |
or eax, eax |
jz .exit |
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2] |
call button._.negative_button |
.exit: |
ret |
align 4 |
;------------------------------------------------------------------------------ |
sys_button_deactivate_handler: ;/////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
;> 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 |
;------------------------------------------------------------------------------ |
call button._.find_button |
or eax, eax |
jz .exit |
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2] |
call button._.negative_button |
.exit: |
ret |
align 4 |
;------------------------------------------------------------------------------ |
sys_button_perform_handler: ;////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
;> 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 |
;============================================================================== |
;///// private functions ////////////////////////////////////////////////////// |
;============================================================================== |
;------------------------------------------------------------------------------ |
button._.find_button: ;//////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Find system button by specified process slot, id and coordinates |
;------------------------------------------------------------------------------ |
;> eax = pack[8(process slot), 24(button id)] or 0 |
;> ebx = pack[16(button x coord), 16(button y coord)] |
;------------------------------------------------------------------------------ |
;< eax = pointer to SYS_BUTTON struct or 0 |
;------------------------------------------------------------------------------ |
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 .not_found |
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 |
; okay, return it |
mov eax, esi |
jmp .exit |
.not_found: |
xor eax, eax |
.exit: |
pop edi esi edx ecx |
ret |
;------------------------------------------------------------------------------ |
button._.dececx: ;///////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
sub cl, 0x20 |
jnc @f |
xor cl, cl |
@@: |
sub ch, 0x20 |
jnc @f |
xor ch, ch |
@@: |
rol ecx, 16 |
sub cl, 0x20 |
jnc @f |
xor cl, cl |
@@: |
rol ecx, 16 |
ret |
;------------------------------------------------------------------------------ |
button._.incecx: ;///////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
add cl, 0x20 |
jnc @f |
or cl, -1 |
@@: |
add ch, 0x20 |
jnc @f |
or ch, -1 |
@@: |
rol ecx, 16 |
add cl, 0x20 |
jnc @f |
or cl, -1 |
@@: |
rol ecx, 16 |
ret |
;------------------------------------------------------------------------------ |
button._.incecx2: ;//////////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
add cl, 0x14 |
jnc @f |
or cl, -1 |
@@: |
add ch, 0x14 |
jnc @f |
or ch, -1 |
@@: |
rol ecx, 16 |
add cl, 0x14 |
jnc @f |
or cl, -1 |
@@: |
rol ecx, 16 |
ret |
;------------------------------------------------------------------------------ |
button._.button_dececx: ;////////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? <description> |
;------------------------------------------------------------------------------ |
cmp [buttontype], 1 |
jne .finish |
push eax |
mov al, 1 |
cmp edi, 20 |
jg @f |
mov al, 2 |
@@: |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
sub ch, al |
jnc @f |
xor ch, ch |
@@: |
rol ecx, 16 |
sub cl, al |
jnc @f |
xor cl, cl |
@@: |
rol ecx, 16 |
pop eax |
.finish: |
ret |
;------------------------------------------------------------------------------ |
button._.negative_button: ;//////////////////////////////////////////////////// |
;------------------------------------------------------------------------------ |
;? Invert system button border |
;------------------------------------------------------------------------------ |
; if requested, do not display button border on press. |
test ebx, 0x20000000 |
jnz .exit |
pushad |
xchg esi, eax |
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] |
push eax ebx |
pop edx ecx |
rol eax, 16 |
rol ebx, 16 |
add ax, cx |
add bx, dx |
mov esi, 0x01000000 |
call draw_rectangle.forced |
popad |
.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 |
Added: svn:mergeinfo |
/kernel/branches/net/gui/skincode.inc |
---|
0,0 → 1,529 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
cmp ebx, 32*1024 |
jb @f |
mov ebx, 32*1024 |
;-------------------------------------- |
align 4 |
@@: |
lea ecx, [ebx+3] |
shr ecx, 2 |
mov esi, eax |
mov edi, skin_data |
rep movsd |
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 |
push 2 |
pop eax |
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, 127 |
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 |
;-------------------------------------- |
align 4 |
.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 @f |
mov edx, skin_inactive.left.data |
;-------------------------------------- |
align 4 |
@@: |
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 @f |
mov edx, skin_inactive.oper.data |
;-------------------------------------- |
align 4 |
@@: |
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 @f |
mov eax, [skin_inactive.left.width] |
mov edx, skin_inactive.base.data |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
pop edx ecx ebx eax |
dec eax |
jnz .baseskinloop |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
_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 |
;-------------------------------------- |
align 4 |
@@: |
cmp dword[skin_data], '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 [drawbar] |
call vesa20_drawbar |
jmp draw_clientbar |
;-------------------------------------- |
align 4 |
@@: |
mov al, [esp+32+4+4] |
call drawwindow_IV_caption |
;-------------------------------------- |
align 4 |
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 [drawbar] |
call vesa20_drawbar |
;-------------------------------------- |
align 4 |
_noinside2: |
cmp dword[skin_data], '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, [CURRENT_TASK] |
mov [eax], bx |
add eax, 2 ; save button id number |
mov bx, 1 |
mov [eax], bx |
add eax, 2 ; x start |
xor ebx, ebx |
cmp [skin_btn_close.left], 0 |
jge _bCx_at_right |
mov ebx, [esp] |
mov ebx, [ebx+WDATA.box.width] |
inc ebx |
;-------------------------------------- |
align 4 |
_bCx_at_right: |
add ebx, [skin_btn_close.left] |
mov [eax], bx |
add eax, 2 ; x size |
mov ebx, [skin_btn_close.width] |
dec ebx |
mov [eax], bx |
add eax, 2 ; y start |
mov ebx, [skin_btn_close.top] |
mov [eax], bx |
add eax, 2 ; y size |
mov ebx, [skin_btn_close.height] |
dec ebx |
mov [eax], bx |
;* 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, [CURRENT_TASK] |
mov [eax], bx |
add eax, 2 ; save button id number |
mov bx, 65535;999 |
mov [eax], bx |
add eax, 2 ; x start |
xor ebx, ebx |
cmp [skin_btn_minimize.left], 0 |
jge _bMx_at_right |
mov ebx, [esp] |
mov ebx, [ebx+WDATA.box.width] |
inc ebx |
;-------------------------------------- |
align 4 |
_bMx_at_right: |
add ebx, [skin_btn_minimize.left] |
mov [eax], bx |
add eax, 2 ; x size |
mov ebx, [skin_btn_minimize.width] |
dec ebx |
mov [eax], bx |
add eax, 2 ; y start |
mov ebx, [skin_btn_minimize.top] |
mov [eax], bx |
add eax, 2 ; y size |
mov ebx, [skin_btn_minimize.height] |
dec ebx |
mov [eax], bx |
;-------------------------------------- |
align 4 |
no_skin_add_button: |
pop edi |
popa |
ret 4 |
;------------------------------------------------------------------------------ |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui/skindata.inc |
---|
0,0 → 1,64 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/gui |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/kernel.asm |
---|
0,0 → 1,5662 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
;; |
;; 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 equ 1 ; make irq 3 and irq 4 available for PCI devices |
; Enabling the next line will enable serial output console |
debug_com_base equ 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" |
lang fix en |
include "const.inc" |
max_processes equ 255 |
tss_step equ (128+8192) ; tss & i/o - 65535 ports, * 256=557056*4 |
os_stack equ (os_data_l-gdts) ; GDTs |
os_code equ (os_code_l-gdts) |
graph_data equ (3+graph_data_l-gdts) |
tss0 equ (tss0_l-gdts) |
app_code equ (3+app_code_l-gdts) |
app_data equ (3+app_data_l-gdts) |
app_tls equ (3+tls_data_l-gdts) |
pci_code_sel equ (pci_code_32-gdts) |
pci_data_sel equ (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 |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 16 BIT ENTRY FROM BOOTSECTOR ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
use16 |
org 0x0 |
jmp start_of_code |
if lang eq sp |
include "kernelsp.inc" ; spanish kernel messages |
else |
version db 'Kolibri OS network development ',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 |
; 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 |
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" |
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, 0x006CC00 ; 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 |
xor esi, esi |
mov edi, (BOOT_VAR-OS_BASE) |
mov ecx, 0x10000 / 4 |
rep movsd |
mov edi, 0x1000 |
mov ecx, 0xf000 / 4 |
rep stosd |
call test_cpu |
bts [cpu_caps-OS_BASE], CAPS_TSC ;force use rdtsc |
call check_acpi |
call init_BIOS32 |
; MEMORY MODEL |
call mem_test |
call init_mem |
call init_page_map |
; ENABLE PAGING |
mov eax, sys_pgdir-OS_BASE |
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 |
org $-0x10000 |
include "boot/shutdown.inc" ; shutdown or restart |
org $+0x10000 |
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 |
bt [cpu_caps], CAPS_PGE |
jnc @F |
or dword [sys_pgdir+(OS_BASE shr 20)], PG_GLOBAL |
mov ebx, cr4 |
or ebx, CR4_PGE |
mov cr4, ebx |
@@: |
xor eax, eax |
mov dword [sys_pgdir], eax |
mov dword [sys_pgdir+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 |
; SAVE REAL MODE VARIABLES |
mov ax, [BOOT_VAR + BOOT_IDE_BASE_ADDR] |
mov [IDEContrRegsBaseAddr], ax |
; --------------- APM --------------------- |
; init selectors |
mov ebx, [BOOT_VAR+BOOT_APM_ENTRY] ; offset of APM entry point |
movzx eax, word [BOOT_VAR+BOOT_APM_CODE_32] ; real-mode segment base address of |
; protected-mode 32-bit code segment |
movzx ecx, word [BOOT_VAR+BOOT_APM_CODE_16]; real-mode segment base address of |
; protected-mode 16-bit code segment |
movzx edx, word [BOOT_VAR+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, [BOOT_VAR + BOOT_APM_VERSION] ; version & flags |
mov [apm_vf], eax |
; ----------------------------------------- |
mov al, [BOOT_VAR+BOOT_DMA] ; DMA access |
mov [allow_dma_access], al |
movzx eax, byte [BOOT_VAR+BOOT_BPP] ; bpp |
mov [ScreenBPP], al |
mov [_display.bpp], eax |
mov [_display.vrefresh], 60 |
movzx eax, word [BOOT_VAR+BOOT_X_RES]; X max |
mov [_display.width], eax |
mov [display_width_standard], eax |
dec eax |
mov [Screen_Max_X], eax |
mov [screen_workarea.right], eax |
movzx eax, word [BOOT_VAR+BOOT_Y_RES]; Y max |
mov [_display.height], eax |
mov [display_height_standard], eax |
dec eax |
mov [Screen_Max_Y], eax |
mov [screen_workarea.bottom], eax |
movzx eax, word [BOOT_VAR+BOOT_VESA_MODE]; screen mode |
mov [SCR_MODE], eax |
; mov eax, [BOOT_VAR+0x9014] ; Vesa 1.2 bnk sw add |
; mov [BANK_SWITCH], eax |
mov [BytesPerScanLine], word 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_VAR+BOOT_PITCH] ; for other modes |
mov [BytesPerScanLine], ax |
mov [_display.pitch], eax |
@@: |
mov eax, [_display.width] |
mul [_display.height] |
mov [_WinMapSize], 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 |
mov esi, BOOT_VAR+0x9080 |
movzx ecx, byte [esi-1] |
mov [NumBiosDisks], ecx |
mov edi, BiosDisksData |
rep movsd |
; GRAPHICS ADDRESSES |
mov eax, [BOOT_VAR+BOOT_LFB] |
mov [LFBAddress], eax |
cmp [SCR_MODE], word 0100000000000000b |
jge setvesa20 |
cmp [SCR_MODE], word 0x13 ; EGA 320*200 256 colors |
je v20ga32 |
jmp v20ga24 |
setvesa20: |
mov [PUTPIXEL], dword Vesa20_putpixel24 ; Vesa 2.0 |
mov [GETPIXEL], dword Vesa20_getpixel24 |
cmp [ScreenBPP], byte 24 |
jz v20ga24 |
v20ga32: |
mov [PUTPIXEL], dword Vesa20_putpixel32 |
mov [GETPIXEL], dword Vesa20_getpixel32 |
jmp no_mode_0x12 |
v20ga24: |
cmp [SCR_MODE], word 0x12 ; 16 C VGA 640x480 |
jne no_mode_0x12 |
mov [PUTPIXEL], dword VGA_putpixel |
mov [GETPIXEL], dword Vesa20_getpixel32 |
no_mode_0x12: |
mov [MOUSE_PICTURE], dword mousepointer |
mov [_display.check_mouse], check_mouse_area_for_putpixel |
mov [_display.check_m_pixel], check_mouse_area_for_getpixel |
; -------- 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 3116 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 150 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_SW |
stdcall alloc_page |
inc eax |
mov [SLOT_BASE+256+APPDATA.io_map], eax |
stdcall map_page, tss+0x80, eax, PG_SW |
stdcall alloc_page |
inc eax |
mov dword [SLOT_BASE+256+APPDATA.io_map+4], eax |
stdcall map_page, tss+0x1080, eax, PG_SW |
; LOAD IDT |
call build_interrupt_table ;lidt is executed |
;lidt [idtreg] |
call init_kernel_heap |
stdcall kernel_alloc, RING0_STACK_SIZE+512 |
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 [LFBSize], 0xC00000 |
call init_LFB |
call init_fpu |
call init_malloc |
stdcall alloc_kernel_space, 0x51000 |
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_pdir], 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, [_WinMapSize] |
mov [_WinMapAddress], eax |
xor eax, eax |
inc eax |
mov [CURRENT_TASK], eax ;dword 1 |
mov [TASK_COUNT], eax ;dword 1 |
mov [TASK_BASE], dword TASK_DATA |
mov [current_slot], SLOT_BASE+256 |
; set background |
mov [BgrDrawMode], eax |
mov [BgrDataWidth], eax |
mov [BgrDataHeight], eax |
mov [mem_BACKGROUND], 4 |
mov [img_background], static_background_data |
; SET UP OS TASK |
mov esi, boot_setostask |
call boot_log |
xor eax, eax |
mov dword [SLOT_BASE+APPDATA.fpu_state], fpu_data |
mov dword [SLOT_BASE+APPDATA.exc_handler], eax |
mov dword [SLOT_BASE+APPDATA.except_mask], eax |
; name for OS/IDLE process |
mov dword [SLOT_BASE+256+APPDATA.app_name], dword 'OS/I' |
mov dword [SLOT_BASE+256+APPDATA.app_name+4], dword 'DLE ' |
mov edi, [os_stack_seg] |
mov dword [SLOT_BASE+256+APPDATA.pl0_stack], edi |
add edi, 0x2000-512 |
mov dword [SLOT_BASE+256+APPDATA.fpu_state], edi |
mov dword [SLOT_BASE+256+APPDATA.saved_esp0], edi; just for case |
mov dword [SLOT_BASE+256+APPDATA.terminate_protection], 80000001h |
mov esi, fpu_data |
mov ecx, 512/4 |
cld |
rep movsd |
mov dword [SLOT_BASE+256+APPDATA.exc_handler], eax |
mov dword [SLOT_BASE+256+APPDATA.except_mask], eax |
mov ebx, SLOT_BASE+256+APP_OBJ_OFFSET |
mov dword [SLOT_BASE+256+APPDATA.fd_obj], ebx |
mov dword [SLOT_BASE+256+APPDATA.bk_obj], ebx |
mov dword [SLOT_BASE+256+APPDATA.cur_dir], sysdir_path |
mov dword [SLOT_BASE+256+APPDATA.tls_base], eax |
; task list |
mov dword [TASK_DATA+TASKDATA.mem_start], eax; process base address |
inc eax |
mov dword [CURRENT_TASK], eax |
mov dword [TASK_COUNT], eax |
mov [current_slot], SLOT_BASE+256 |
mov [TASK_BASE], dword TASK_DATA |
mov byte[TASK_DATA+TASKDATA.wnd_number], al ; on screen number |
mov dword [TASK_DATA+TASKDATA.pid], eax ; process id number |
mov [SLOT_BASE + 256 + APPDATA.dir_table], sys_pgdir - OS_BASE |
; 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 |
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 hard drives IRQs (IRQ14, IRQ15) |
; they are used: when partitions are scanned, hd_read relies on timer |
call unmask_timer |
stdcall enable_irq, 2 ; @#$%! PIC |
stdcall enable_irq, 6 ; FDD |
stdcall enable_irq, 13 ; co-processor |
stdcall enable_irq, 14 |
stdcall enable_irq, 15 |
mov esi, boot_enablint_ide |
call boot_log |
; Enable interrupts in IDE controller |
mov al, 0 |
mov dx, 0x3F6 |
out dx, al |
mov dl, 0x76 |
out dx, al |
;!!!!!!!!!!!!!!!!!!!!!!!!!! |
; mov esi, boot_detectdisks |
; call boot_log |
;include 'detect/disks.inc' |
mov esi, boot_detectfloppy |
call boot_log |
include 'detect/dev_fd.inc' |
mov esi, boot_detecthdcd |
call boot_log |
include 'detect/dev_hdcd.inc' |
mov esi, boot_getcache |
call boot_log |
include 'detect/getcache.inc' |
mov esi, boot_detectpart |
call boot_log |
include 'detect/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 [dma_hdd],1 |
; CALCULATE FAT CHAIN FOR RAMDISK |
call calculatefatchain |
if 0 |
mov ax, [OS_BASE+0x10000+bx_from_load] |
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 |
mov [pci_access_enabled], 1 |
call pci_enum |
; 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], eax |
mov [SLOT_BASE+APPDATA.cursor+256], eax |
; READ TSC / SECOND |
mov esi, boot_tsc |
call boot_log |
cli |
rdtsc ;call _rdtsc |
mov ecx, eax |
mov esi, 250 ; wait 1/4 a second |
call delay_ms |
rdtsc ;call _rdtsc |
sti |
sub eax, ecx |
shl eax, 2 |
mov [CPU_FREQ], eax ; save tsc / sec |
; mov ebx, 1000000 |
; div ebx |
; ¢®®¡é¥-â® ¯à®¨§¢®¤¨â¥«ì®áâì ¢ ¤ ®¬ ª®ªà¥â®¬ ¬¥á⥠|
; ᮢ¥à襮 ¥ªà¨â¨ç , ® çâ®¡ë § âªãâì «î¡¨â¥«¥© |
; ®¯â¨¬¨§¨àãîé¨å ª®¬¯¨«ïâ®à®¢ ... |
mov edx, 2251799814 |
mul edx |
shr edx, 19 |
mov [stall_mcs], edx |
; PRINT CPU FREQUENCY |
mov esi, boot_cpufreq |
call boot_log |
mov ebx, edx |
movzx ecx, word [boot_y] |
if lang eq ru |
add ecx, (10+19*6) shl 16 - 10 ; 'Determining amount of memory' |
else if lang eq sp |
add ecx, (10+25*6) shl 16 - 10 ; 'Determining amount of memory' |
else |
add ecx, (10+17*6) shl 16 - 10 ; 'Determining amount of memory' |
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 io permission map |
mov esi, [default_io_map] |
stdcall map_page, esi, [SLOT_BASE+256+APPDATA.io_map], PG_MAP |
add esi, 0x1000 |
stdcall map_page, esi, [SLOT_BASE+256+APPDATA.io_map+4], PG_MAP |
stdcall map_page, tss._io_map_0, \ |
[SLOT_BASE+256+APPDATA.io_map], PG_MAP |
stdcall map_page, tss._io_map_1, \ |
[SLOT_BASE+256+APPDATA.io_map+4], PG_MAP |
mov ax, [OS_BASE+0x10000+bx_from_load] |
; LOAD FIRST APPLICATION |
cli |
; cmp byte [BOOT_VAR+0x9030],1 |
; jne no_load_vrr_m |
; mov ebp, vrr_m |
; call fs_execute_from_sysdir |
; |
;; cmp eax,2 ; if vrr_m app found (PID=2) |
; sub eax,2 |
; jz first_app_found |
; |
;no_load_vrr_m: |
mov ebp, firstapp |
call fs_execute_from_sysdir |
; cmp eax,2 ; continue if a process has been loaded |
test eax, eax |
jns first_app_found |
mov esi, boot_failed |
call boot_log |
mov eax, 0xDEADBEEF ; otherwise halt |
hlt |
first_app_found: |
cli |
;mov [TASK_COUNT],dword 2 |
push 1 |
pop dword [CURRENT_TASK] ; set OS task fisrt |
; SET KEYBOARD PARAMETERS |
mov al, 0xf6 ; reset keyboard, scan enabled |
call kb_write |
test ah, ah |
jnz .no_keyboard |
; wait until 8042 is ready |
xor ecx, ecx |
@@: |
in al, 64h |
and al, 00000010b |
loopnz @b |
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 |
; call kb_read |
; mov al, 111b |
; call kb_write |
; call kb_read |
mov al, 0xF3 ; set repeat rate & delay |
call kb_write |
; call kb_read |
mov al, 0; 30 250 ;00100010b ; 24 500 ;00100100b ; 20 500 |
call kb_write |
; call kb_read |
;// mike.dld [ |
call set_lights |
;// mike.dld ] |
stdcall attach_int_handler, 1, irq1, 0 |
.no_keyboard: |
; SET MOUSE |
stdcall load_driver, szPS2MDriver |
; stdcall load_driver, szCOM_MDriver |
mov esi, boot_setmouse |
call boot_log |
call setmouse |
; Setup serial output console (if enabled) |
if defined debug_com_base |
; 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 |
mov eax, [cpu_count] |
test eax, eax |
jnz @F |
mov al, 1 ; at least one CPU |
@@: |
DEBUGF 1, "K : %d CPU detected\n", eax |
; START MULTITASKING |
; 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 |
cmp [IDEContrRegsBaseAddr], 0 |
setnz [dma_hdd] |
mov [timer_ticks_enable], 1 ; for cd driver |
sti |
call change_task |
jmp osloop |
; Fly :) |
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 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; ; |
; MAIN OS LOOP START ; |
; ; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 32 |
osloop: |
; call [draw_pointer] |
call __sys_draw_pointer |
call window_check_events |
call mouse_check_events |
call checkmisc |
call checkVga_N13 |
call stack_handler |
call checkidle |
call check_fdd_motor_status |
call check_ATAPI_device_event |
call check_lights_state |
call check_timers |
jmp osloop |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; ; |
; MAIN OS LOOP END ; |
; ; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
checkidle: |
pushad |
call change_task |
jmp idle_loop_entry |
idle_loop: |
cmp eax, [idlemem] ; eax == [timer_ticks] |
jne idle_exit |
rdtsc ;call _rdtsc |
mov ecx, eax |
hlt |
rdtsc ;call _rdtsc |
sub eax, ecx |
add [idleuse], eax |
idle_loop_entry: |
mov eax, [timer_ticks]; eax = [timer_ticks] |
cmp [check_idle_semaphore], 0 |
je idle_loop |
dec [check_idle_semaphore] |
idle_exit: |
mov [idlemem], eax ; eax == [timer_ticks] |
popad |
ret |
uglobal |
idlemem dd 0x0 |
idleuse dd 0x0 |
idleusesec dd 0x0 |
check_idle_semaphore dd 0x0 |
endg |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; ; |
; 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+4], 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+28+8], dword 0xDF |
mov [eax+64], ecx |
mov [eax+64+4], dword 0xE5 |
mov [eax+64+8], dword 0xFF |
ret |
iglobal |
process_number dd 0x1 |
endg |
set_variables: |
mov ecx, 0x16 ; flush port 0x60 |
.fl60: |
in al, 0x60 |
loop .fl60 |
push eax |
mov ax, [BOOT_VAR+BOOT_Y_RES] |
shr ax, 1 |
shl eax, 16 |
mov ax, [BOOT_VAR+BOOT_X_RES] |
shr ax, 1 |
mov [MOUSE_X], eax |
xor eax, eax |
mov [BTN_ADDR], dword BUTTON_INFO ; address of button list |
mov byte [MOUSE_BUFF_COUNT], al ; mouse buffer |
mov byte [KEY_COUNT], al ; keyboard buffer |
mov byte [BTN_COUNT], al ; button buffer |
; mov [MOUSE_X],dword 100*65536+100 ; mouse x/y |
;!! IP 04.02.2005: |
mov byte [DONT_SWITCH], al; change task if possible |
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: |
;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_TASK] |
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] |
and ecx, not 0x80000000 ; force counted string |
mov eax, [esp+64+8] ; background color (if given) |
mov edi, [esp+64+4] |
jmp dtext |
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=cd base 1, pri.master 2, pri slave 3 sec master, 4 sec slave |
; 5=system language, 1eng 2fi 3ger 4rus |
; 7=hd base 1, pri.master 2, pri slave 3 sec master, 4 sec slave |
; 8=fat32 partition in hd |
; 9 |
; 10 = sound dma channel |
; 11 = enable lba read |
; 12 = enable pci access |
and [esp+32], dword 0 |
dec ebx ; MIDI |
jnz nsyse1 |
cmp ecx, 0x100 |
jb nsyse1 |
mov esi, 65535 |
cmp esi, ecx |
jb nsyse1 |
mov [midi_base], cx ;bx |
mov word [mididp], cx;bx |
inc cx ;bx |
mov word [midisp], cx;bx |
ret |
iglobal |
midi_base dw 0 |
endg |
nsyse1: |
dec ebx ; KEYBOARD |
jnz nsyse2 |
mov edi, [TASK_BASE] |
mov eax, [edi+TASKDATA.mem_start] |
add eax, edx |
dec ecx |
jnz kbnobase |
mov ebx, keymap |
mov ecx, 128 |
call memmove |
ret |
kbnobase: |
dec ecx |
jnz kbnoshift |
mov ebx, keymap_shift |
mov ecx, 128 |
call memmove |
ret |
kbnoshift: |
dec ecx |
jnz kbnoalt |
mov ebx, keymap_alt |
mov ecx, 128 |
call memmove |
ret |
kbnoalt: |
sub ecx, 6 |
jnz kbnocountry |
mov word [keyboard], dx |
ret |
kbnocountry: |
mov [esp+32], dword 1 |
ret |
nsyse2: |
dec ebx ; CD |
jnz nsyse4 |
test ecx, ecx |
jz nosesl |
cmp ecx, 4 |
ja nosesl |
mov [cd_base], cl |
dec ecx |
jnz noprma |
mov [cdbase], 0x1f0 |
mov [cdid], 0xa0 |
noprma: |
dec ecx |
jnz noprsl |
mov [cdbase], 0x1f0 |
mov [cdid], 0xb0 |
noprsl: |
dec ecx |
jnz nosema |
mov [cdbase], 0x170 |
mov [cdid], 0xa0 |
nosema: |
dec ecx |
jnz nosesl |
mov [cdbase], 0x170 |
mov [cdid], 0xb0 |
nosesl: |
ret |
iglobal |
cd_base db 0 |
endg |
nsyse4: |
sub ebx, 2 ; SYSTEM LANGUAGE |
jnz nsyse5 |
mov [syslang], ecx |
ret |
nsyse5: |
sub ebx, 2 ; HD BASE |
jnz nsyse7 |
test ecx, ecx |
jz nosethd |
cmp ecx, 4 |
ja nosethd |
mov [hd_base], cl |
cmp ecx, 1 |
jnz noprmahd |
mov [hdbase], 0x1f0 |
and dword [hdid], 0x0 |
mov dword [hdpos], ecx |
; call set_FAT32_variables |
noprmahd: |
cmp ecx, 2 |
jnz noprslhd |
mov [hdbase], 0x1f0 |
mov [hdid], 0x10 |
mov dword [hdpos], ecx |
; call set_FAT32_variables |
noprslhd: |
cmp ecx, 3 |
jnz nosemahd |
mov [hdbase], 0x170 |
and dword [hdid], 0x0 |
mov dword [hdpos], ecx |
; call set_FAT32_variables |
nosemahd: |
cmp ecx, 4 |
jnz noseslhd |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
mov dword [hdpos], ecx |
; call set_FAT32_variables |
noseslhd: |
call reserve_hd1 |
call reserve_hd_channel |
call free_hd_channel |
and dword [hd1_status], 0 ; free |
nosethd: |
ret |
iglobal |
hd_base db 0 |
endg |
nsyse7: |
; cmp eax,8 ; HD PARTITION |
dec ebx |
jnz nsyse8 |
mov [fat32part], ecx |
; call set_FAT32_variables |
call reserve_hd1 |
call reserve_hd_channel |
call free_hd_channel |
; pusha |
call choice_necessity_partition_1 |
; popa |
and dword [hd1_status], 0 ; free |
ret |
nsyse8: |
; cmp eax,11 ; ENABLE LBA READ |
and ecx, 1 |
sub ebx, 3 |
jnz no_set_lba_read |
mov [lba_read_enabled], ecx |
ret |
no_set_lba_read: |
; cmp eax,12 ; ENABLE PCI ACCESS |
dec ebx |
jnz sys_setup_err |
mov [pci_access_enabled], ecx |
ret |
sys_setup_err: |
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=cd base 1, pri.master 2, pri slave 3 sec master, 4 sec slave |
; 5=system language, 1eng 2fi 3ger 4rus |
; 7=hd base 1, pri.master 2, pri slave 3 sec master, 4 sec slave |
; 8=fat32 partition in hd |
; 9=get hs timer tic |
; cmp eax,1 |
dec ebx |
jnz ngsyse1 |
movzx eax, [midi_base] |
mov [esp+32], eax |
ret |
ngsyse1: |
; cmp eax,2 |
dec ebx |
jnz ngsyse2 |
mov edi, [TASK_BASE] |
mov ebx, [edi+TASKDATA.mem_start] |
add ebx, edx |
; cmp ebx,1 |
dec ecx |
jnz kbnobaseret |
mov eax, keymap |
mov ecx, 128 |
call memmove |
ret |
kbnobaseret: |
; cmp ebx,2 |
dec ecx |
jnz kbnoshiftret |
mov eax, keymap_shift |
mov ecx, 128 |
call memmove |
ret |
kbnoshiftret: |
; cmp ebx,3 |
dec ecx |
jne kbnoaltret |
mov eax, keymap_alt |
mov ecx, 128 |
call memmove |
ret |
kbnoaltret: |
; cmp ebx,9 |
sub ecx, 6 |
jnz ngsyse2 |
movzx eax, word [keyboard] |
mov [esp+32], eax |
ret |
ngsyse2: |
; cmp eax,3 |
dec ebx |
jnz ngsyse3 |
movzx eax, [cd_base] |
mov [esp+32], eax |
ret |
ngsyse3: |
; cmp eax,5 |
sub ebx, 2 |
jnz ngsyse5 |
mov eax, [syslang] |
mov [esp+32], eax |
ret |
ngsyse5: |
; cmp eax,7 |
sub ebx, 2 |
jnz ngsyse7 |
movzx eax, [hd_base] |
mov [esp+32], eax |
ret |
ngsyse7: |
; cmp eax,8 |
dec ebx |
jnz ngsyse8 |
mov eax, [fat32part] |
mov [esp+32], eax |
ret |
ngsyse8: |
; cmp eax,9 |
dec ebx |
jnz ngsyse9 |
mov eax, [timer_ticks];[0xfdf0] |
mov [esp+32], eax |
ret |
ngsyse9: |
; cmp eax,11 |
sub ebx, 2 |
jnz ngsyse11 |
mov eax, [lba_read_enabled] |
mov [esp+32], eax |
ret |
ngsyse11: |
; cmp eax,12 |
dec ebx |
jnz ngsyse12 |
mov eax, [pci_access_enabled] |
mov [esp+32], eax |
ret |
ngsyse12: |
mov [esp+32], dword 1 |
ret |
get_timer_ticks: |
mov eax, [timer_ticks] |
ret |
iglobal |
align 4 |
mousefn dd msscreen, mswin, msbutton, msset |
dd app_load_cursor |
dd app_set_cursor |
dd app_delete_cursor |
dd msz |
endg |
readmousepos: |
; eax=0 screen relative |
; eax=1 window relative |
; eax=2 buttons pressed |
; eax=3 set mouse pos ; reserved |
; eax=4 load cursor |
; eax=5 set cursor |
; eax=6 delete cursor ; reserved |
; eax=7 get mouse_z |
cmp ebx, 7 |
ja msset |
jmp [mousefn+ebx*4] |
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_TASK] |
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 |
msz: |
mov edi, [TASK_COUNT] |
movzx edi, word [WIN_POS + edi*2] |
cmp edi, [CURRENT_TASK] |
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 |
msset: |
ret |
app_load_cursor: |
cmp ecx, OS_BASE |
jae msset |
stdcall load_cursor, ecx, edx |
mov [esp+36-4], eax |
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 |
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], 3; terminate this program |
waitterm: ; wait here for termination |
mov ebx, 100 |
call delay_hs |
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 ecx, [Screen_Max_X] |
; inc ecx |
; mul ecx |
mov eax, [d_width_calc_area + eax*4] |
add eax, [_WinMapAddress] |
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 |
popfd |
; call [draw_pointer] |
call __sys_draw_pointer |
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 |
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, 1 |
jl exit_for_anyone |
cmp ecx, 4 |
jg exit_for_anyone |
mov [BOOT_VAR+0x9030], cl |
mov eax, [TASK_COUNT] |
mov [SYS_SHUTDOWN], al |
mov [shutdown_processes], eax |
and dword [esp+32], 0 |
exit_for_anyone: |
ret |
uglobal |
shutdown_processes: |
dd 0x0 |
endg |
;------------------------------------------------------------------------------ |
sysfn_terminate: ; 18.2 = TERMINATE |
push ecx |
cmp ecx, 2 |
jb noprocessterminate |
mov edx, [TASK_COUNT] |
cmp ecx, edx |
ja noprocessterminate |
mov eax, [TASK_COUNT] |
shl ecx, 5 |
mov edx, [ecx+CURRENT_TASK+TASKDATA.pid] |
add ecx, CURRENT_TASK+TASKDATA.state |
cmp byte [ecx], 9 |
jz noprocessterminate |
push ecx edx |
lea edx, [(ecx-(CURRENT_TASK 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 |
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 MEM_Heap_UnLock |
cmp edx, [application_table_status]; clear app table stat |
jne noatsc |
and [application_table_status], 0 |
noatsc: |
noprocessterminate: |
add esp, 4 |
ret |
;------------------------------------------------------------------------------ |
sysfn_terminate2: |
;lock application_table_status mutex |
.table_status: |
cli |
cmp [application_table_status], 0 |
je .stf |
sti |
call change_task |
jmp .table_status |
.stf: |
call set_application_table_status |
mov eax, ecx |
call pid_to_slot |
test eax, eax |
jz .not_found |
mov ecx, eax |
cli |
call sysfn_terminate |
and [application_table_status], 0 |
sti |
and dword [esp+32], 0 |
ret |
.not_found: |
mov [application_table_status], 0 |
or dword [esp+32], -1 |
ret |
;------------------------------------------------------------------------------ |
sysfn_deactivate: ; 18.1 = DEACTIVATE WINDOW |
cmp ecx, 2 |
jb .nowindowdeactivate |
cmp ecx, [TASK_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 |
xor eax, eax |
mov byte[MOUSE_BACKGROUND], al |
mov byte[DONT_DRAW_MOUSE], al |
mov byte[MOUSE_DOWN], 0 |
call syscall_display_settings._.calculate_whole_screen |
call syscall_display_settings._.redraw_whole_screen |
.nowindowdeactivate: |
ret |
;------------------------------------------------------------------------------ |
sysfn_activate: ; 18.3 = ACTIVATE WINDOW |
cmp ecx, 2 |
jb .nowindowactivate |
cmp ecx, [TASK_COUNT] |
ja .nowindowactivate |
mov [window_minimize], 2; restore window if minimized |
movzx esi, word [WIN_STACK + ecx*2] |
cmp esi, [TASK_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 |
;------------------------------------------------------------------------------ |
sysfn_getidletime: ; 18.4 = GET IDLETIME |
mov eax, [idleusesec] |
mov [esp+32], eax |
ret |
;------------------------------------------------------------------------------ |
sysfn_getcpuclock: ; 18.5 = GET TSC/SEC |
mov eax, [CPU_FREQ] |
mov [esp+32], eax |
ret |
;------------------------------------------------------------------------------ |
; SAVE ramdisk to /hd/1/menuet.img |
;!!!!!!!!!!!!!!!!!!!!!!!! |
include 'blkdev/rdsave.inc' |
;!!!!!!!!!!!!!!!!!!!!!!!! |
;------------------------------------------------------------------------------ |
align 4 |
sysfn_getactive: ; 18.7 = get active window |
mov eax, [TASK_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 |
ret |
;------------------------------------------------------------------------------ |
align 4 |
sysfn_getdiskinfo: ; 18.11 = get disk info table |
; cmp ecx,1 |
dec ecx |
jnz full_table |
small_table: |
call for_all_tables |
mov ecx, 10 |
cld |
rep movsb |
ret |
for_all_tables: |
mov edi, edx |
mov esi, DRIVE_DATA |
ret |
full_table: |
; cmp ecx,2 |
dec ecx |
jnz exit_for_anyone |
call for_all_tables |
mov ecx, 16384 |
cld |
rep movsd |
ret |
;------------------------------------------------------------------------------ |
sysfn_lastkey: ; 18.12 = return 0 (backward compatibility) |
and dword [esp+32], 0 |
ret |
;------------------------------------------------------------------------------ |
sysfn_getversion: ; 18.13 = get kernel ID and version |
mov edi, ecx |
mov esi, version_inf |
mov ecx, version_end-version_inf |
rep movsb |
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 |
; removed here by <Lrz> |
; call mouse_centered |
;* mouse centered - start code- Mario79 |
;mouse_centered: |
; push eax |
mov eax, [Screen_Max_X] |
shr eax, 1 |
mov [MOUSE_X], ax |
mov eax, [Screen_Max_Y] |
shr eax, 1 |
mov [MOUSE_Y], ax |
; ret |
;* mouse centered - end code- Mario79 |
xor eax, eax |
and [esp+32], eax |
; pop eax |
ret |
;------------------------------------------------------------------------------ |
align 4 |
sysfn_mouse_acceleration: ; 18.19 = set/get mouse features |
test ecx, ecx; get mouse speed factor |
jnz .set_mouse_acceleration |
xor eax, eax |
mov ax, [mouse_speed_factor] |
mov [esp+32], eax |
ret |
.set_mouse_acceleration: |
; cmp ecx,1 ; set mouse speed factor |
dec ecx |
jnz .get_mouse_delay |
mov [mouse_speed_factor], dx |
ret |
.get_mouse_delay: |
; cmp ecx,2 ; get mouse delay |
dec ecx |
jnz .set_mouse_delay |
mov eax, [mouse_delay] |
mov [esp+32], eax |
ret |
.set_mouse_delay: |
; cmp ecx,3 ; set mouse delay |
dec ecx |
jnz .set_pointer_position |
mov [mouse_delay], edx |
ret |
.set_pointer_position: |
; cmp ecx,4 ; set mouse pointer position |
dec ecx |
jnz .set_mouse_button |
cmp dx, word[Screen_Max_Y] |
ja .end |
rol edx, 16 |
cmp dx, word[Screen_Max_X] |
ja .end |
mov [MOUSE_X], edx |
ret |
.set_mouse_button: |
; cmp ecx,5 ; set mouse button features |
dec ecx |
jnz .end |
mov [BTN_DOWN], dl |
mov [mouse_active], 1 |
.end: |
ret |
;------------------------------------------------------------------------------ |
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, [BytesPerScanLine] |
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 |
dd __REV__ |
version_end: |
endg |
;------------------------------------------------------------------------------ |
align 4 |
sys_cachetodiskette: |
cmp ebx, 1 |
jne .no_floppy_a_save |
mov [flp_number], 1 |
jmp .save_image_on_floppy |
;-------------------------------------- |
align 4 |
.no_floppy_a_save: |
cmp ebx, 2 |
jne .no_floppy_b_save |
mov [flp_number], 2 |
;-------------------------------------- |
align 4 |
.save_image_on_floppy: |
call save_image |
mov [esp + 32], dword 0 |
cmp [FDC_Status], 0 |
je .yes_floppy_save |
;-------------------------------------- |
align 4 |
.no_floppy_b_save: |
mov [esp + 32], dword 1 |
;-------------------------------------- |
align 4 |
.yes_floppy_save: |
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 |
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_TASK] |
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], DONT_FREE_BLOCK |
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_UW |
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_TASK] |
cmp [bgrlockpid], eax |
jnz .err |
mov eax, ecx |
mov ebx, ecx |
shr eax, 12 |
mov ecx, [page_tabs+(eax-1)*4] |
test cl, USED_BLOCK+DONT_FREE_BLOCK |
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 DONT_FREE_BLOCK |
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 eax, [BG_Rect_X_left_right] |
mov [esp + 32], eax ; eax = [left]*65536 + [right] |
mov eax, [BG_Rect_Y_top_bottom] |
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, [Screen_Max_X] |
mov ebx, [Screen_Max_Y] |
; check [right] |
cmp cx, ax |
ja .exit |
; check [left] |
ror ecx, 16 |
cmp cx, ax |
ja .exit |
; check [bottom] |
cmp dx, bx |
ja .exit |
; check [top] |
ror edx, 16 |
cmp dx, bx |
ja .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 byte[REDRAW_BACKGROUND] |
;-------------------------------------- |
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, [Screen_Max_X] |
mov ebx, [Screen_Max_Y] |
mov [draw_data+32 + RECT.right], eax |
mov [draw_data+32 + RECT.bottom], ebx |
pop ebx eax |
inc byte[REDRAW_BACKGROUND] |
ret |
;------------------------------------------------------------------------------ |
align 4 |
sys_getbackground: |
; cmp eax,1 ; SIZE |
dec ebx |
jnz nogb1 |
mov eax, [BgrDataWidth] |
shl eax, 16 |
mov ax, [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_TASK] ; TOP OF WINDOW STACK |
movzx ecx, word [WIN_STACK + ebx * 2] |
mov edx, [TASK_COUNT] |
cmp ecx, edx |
jne .finish |
cmp [KEY_COUNT], byte 0 |
je .finish |
movzx eax, 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 |
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_TASK] ; TOP OF WINDOW STACK |
mov [esp + 32], dword 1 |
movzx ecx, word [WIN_STACK + ebx * 2] |
mov edx, [TASK_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 |
; |
cmp ecx, -1 ; who am I ? |
jne .no_who_am_i |
mov ecx, [CURRENT_TASK] |
.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+CURRENT_TASK+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.mem_size] |
mov eax, std_application_base_address |
.os_mem: |
stosd |
lea eax, [edx-1] |
stosd |
; +30: PID/TID |
mov eax, [ecx+CURRENT_TASK+TASKDATA.pid] |
stosd |
; window position and size |
push esi |
lea esi, [ecx + window_data + WDATA.box] |
movsd |
movsd |
movsd |
movsd |
; Process state (+50) |
mov eax, dword [ecx+CURRENT_TASK+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+CURRENT_TASK+TASKDATA.event_mask] |
stosd |
pop esi |
pop edi |
.nofillbuf: |
; return number of processes |
mov eax, [TASK_COUNT] |
mov [esp+32], eax |
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_TASK] |
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 - CURRENT_TASK |
mov [edx + RECT.left], 0 |
mov [edx + RECT.top], 0 |
mov eax, [Screen_Max_X] |
mov [edx + RECT.right], eax |
mov eax, [Screen_Max_Y] |
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 |
;--------------------------------------------------------------------------------------------- |
; check if pixel is allowed to be drawn |
;checkpixel: |
; push eax edx |
;; mov edx, [Screen_Max_X] ; screen x size |
;; inc edx |
;; imul edx, ebx |
; mov edx, [d_width_calc_area + ebx*4] |
; add eax, [_WinMapAddress] |
; mov dl, [eax+edx]; lea eax, [...] |
; xor ecx, ecx |
; mov eax, [CURRENT_TASK] |
; cmp al, dl |
; setne cl |
; pop edx 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, CURRENT_TASK |
mov ecx, [TASK_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, 256 |
add ebx, 32 |
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.event_mask], 100000b ; set event 6 |
;-------------------------------------- |
align 4 |
.skip: |
loop .set_mouse_event |
pop eax |
;-------------------------------------- |
align 4 |
mouse_not_active: |
cmp byte[REDRAW_BACKGROUND], 0 ; background update ? |
jz nobackgr |
cmp [background_defined], 0 |
jz nobackgr |
;-------------------------------------- |
align 4 |
@@: |
push eax |
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] |
pop eax |
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, [TASK_COUNT] |
;-------------------------------------- |
align 4 |
set_bgr_event: |
add edi, 256 |
or [edi+SLOT_BASE+APPDATA.event_mask], 10000b ; set event 5 |
loop set_bgr_event |
pop edi ecx |
; call change_task - because the application must have time to call f.15.8 |
call change_task |
;--------- set event 5 stop ----------- |
dec byte[REDRAW_BACKGROUND] ; got new update request? |
jnz @b |
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 |
mov [MOUSE_BACKGROUND], byte 0 |
;-------------------------------------- |
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], 9 |
jz .nokill |
lea edx, [(edx-(CURRENT_TASK and 1FFFFFFFh))*8+SLOT_BASE] |
cmp [edx+APPDATA.dir_table], sys_pgdir - OS_BASE |
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], byte 3 |
@@: |
add edx, 0x20 |
loop markz |
;-------------------------------------- |
align 4 |
@@: |
no_mark_system_shutdown: |
dec byte [SYS_SHUTDOWN] |
je system_shutdown |
;-------------------------------------- |
align 4 |
noshutdown: |
mov eax, [TASK_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 |
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, [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 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 byte[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 byte[REDRAW_BACKGROUND], dl |
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 byte[REDRAW_BACKGROUND] |
;-------------------------------------- |
align 4 |
newdw8: |
nobgrd: |
mov [eax + WDATA.fl_redraw], byte 1 ; mark as redraw |
;-------------------------------------- |
align 4 |
ricino: |
not_this_task: |
pop ecx |
cmp ecx, [TASK_COUNT] |
jle newdw2 |
pop eax |
popad |
ret |
;----------------------------------------------------------------------------- |
align 4 |
calculatebackground: ; background |
mov edi, [_WinMapAddress] ; set os to use all pixels |
mov eax, 0x01010101 |
mov ecx, [_WinMapSize] |
shr ecx, 2 |
rep stosd |
mov byte[REDRAW_BACKGROUND], 0 ; do not draw background! |
ret |
;----------------------------------------------------------------------------- |
uglobal |
imax dd 0x0 |
endg |
;----------------------------------------------------------------------------- |
align 4 |
delay_ms: ; delay in 1/1000 sec |
push eax |
push ecx |
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 |
;-------------------------------------- |
align 4 |
cnt1: |
in al, 0x61 |
and al, 0x10 |
cmp al, ah |
jz cnt1 |
mov ah, al |
loop cnt1 |
pop ecx |
pop eax |
ret |
;----------------------------------------------------------------------------- |
align 4 |
set_app_param: |
mov edi, [TASK_BASE] |
mov eax, ebx |
btr eax, 3 ; move MOUSE_FILTRATION |
mov ebx, [current_slot] ; bit into event_filter |
setc byte [ebx+APPDATA.event_filter] |
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 |
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 |
;----------------------------------------------------------------------------- |
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 |
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 |
mov eax, [CURRENT_TASK] |
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_read: |
push ecx edx |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
kr_loop: |
in al, 0x64 |
test al, 1 |
jnz kr_ready |
loop kr_loop |
mov ah, 1 |
jmp kr_exit |
kr_ready: |
push ecx |
mov ecx, 32 |
kr_delay: |
loop kr_delay |
pop ecx |
in al, 0x60 |
xor ah, ah |
kr_exit: |
pop edx ecx |
ret |
;----------------------------------------------------------------------------- |
align 4 |
kb_write: |
push ecx edx |
mov dl, al |
; mov ecx,0x1ffff ; last 0xffff, new value in view of fast CPU's |
; kw_loop1: |
; in al,0x64 |
; test al,0x20 |
; jz kw_ok1 |
; loop kw_loop1 |
; mov ah,1 |
; jmp kw_exit |
; kw_ok1: |
in al, 0x60 |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
kw_loop: |
in al, 0x64 |
test al, 2 |
jz kw_ok |
loop kw_loop |
mov ah, 1 |
jmp kw_exit |
kw_ok: |
mov al, dl |
out 0x60, al |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
kw_loop3: |
in al, 0x64 |
test al, 2 |
jz kw_ok3 |
loop kw_loop3 |
mov ah, 1 |
jmp kw_exit |
kw_ok3: |
mov ah, 8 |
kw_loop4: |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
kw_loop5: |
in al, 0x64 |
test al, 1 |
jnz kw_ok4 |
loop kw_loop5 |
dec ah |
jnz kw_loop4 |
kw_ok4: |
xor ah, ah |
kw_exit: |
pop edx ecx |
ret |
;----------------------------------------------------------------------------- |
align 4 |
kb_cmd: |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
c_wait: |
in al, 0x64 |
test al, 2 |
jz c_send |
loop c_wait |
jmp c_error |
c_send: |
mov al, bl |
out 0x64, al |
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's |
c_accept: |
in al, 0x64 |
test al, 2 |
jz c_ok |
loop c_accept |
c_error: |
mov ah, 1 |
jmp c_exit |
c_ok: |
xor ah, ah |
c_exit: |
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 eax, 1 |
movzx ebx, 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 bl, al |
xor eax, eax |
inc eax |
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 0x0 |
endg |
sys_msg_board: |
; eax=1 : write : bl byte to write |
; eax=2 : read : ebx=0 -> no data, ebx=1 -> data in al |
mov ecx, [msg_board_count] |
cmp eax, 1 |
jne .smbl1 |
if defined debug_com_base |
push dx ax |
@@: ; Wait for empty transmit register (yes, this slows down system..) |
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 |
inc ecx |
and ecx, msg_board_data_size - 1 |
mov [msg_board_count], ecx |
mov [check_idle_semaphore], 5 |
ret |
.smbl1: |
cmp eax, 2 |
jne .smbl2 |
test ecx, ecx |
jz .smbl21 |
mov eax, msg_board_data+1 |
mov ebx, msg_board_data |
movzx edx, byte [ebx] |
call memmove |
dec [msg_board_count] |
mov [esp + 36], edx ;eax |
mov [esp + 24], dword 1 |
ret |
.smbl21: |
mov [esp+36], ecx |
mov [esp+24], ecx |
.smbl2: |
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_TASK] |
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_TASK] |
shl eax, 5 |
mov eax, [eax+CURRENT_TASK+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_TASK] |
shl ebx, 5 |
mov ebx, [ebx+CURRENT_TASK+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, [Screen_Max_X] |
shl eax, 16 |
mov ax, [Screen_Max_Y] |
add eax, 0x00010001 |
mov [esp+32], eax |
ret |
.2: ; bits per pixel |
movzx eax, byte [ScreenBPP] |
mov [esp+32], eax |
ret |
.3: ; bytes per scanline |
mov eax, [BytesPerScanLine] |
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 |
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 |
add ebx, ebp |
mov eax, edi |
test ecx, 0x08000000 ; redirect the output to the user area |
jnz dtext |
xor edi, edi |
jmp dtext |
align 4 |
syscall_openramdiskfile: ; OpenRamdiskFile |
mov eax, ebx |
mov ebx, ecx |
mov ecx, edx |
mov edx, esi |
mov esi, 12 |
call fileread |
mov [esp+32], eax |
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, [Screen_Max_X] |
shl eax, 16 |
mov ax, [Screen_Max_Y] |
mov [esp + 32], eax |
ret |
align 4 |
syscall_cdaudio: ; CD |
cmp ebx, 4 |
jb .audio |
jz .eject |
cmp ebx, 5 |
jnz .ret |
.load: |
call .reserve |
call LoadMedium |
;call .free |
jmp .free |
; ret |
.eject: |
call .reserve |
call clear_CD_cache |
call allow_medium_removal |
call EjectMedium |
; call .free |
jmp .free |
; ret |
.audio: |
call sys_cd_audio |
mov [esp+36-4], eax |
.ret: |
ret |
.reserve: |
call reserve_cd |
mov eax, ecx |
shr eax, 1 |
and eax, 1 |
inc eax |
mov [ChannelNumber], ax |
mov eax, ecx |
and eax, 1 |
mov [DiskNumber], al |
call reserve_cd_channel |
and ebx, 3 |
inc ebx |
mov [cdpos], ebx |
add ebx, ebx |
mov cl, 8 |
sub cl, bl |
mov al, [DRIVE_DATA+1] |
shr al, cl |
test al, 2 |
jz .free;.err |
ret |
.free: |
call free_cd_channel |
and [cd_status], 0 |
ret |
.err: |
call .free |
; pop eax |
ret |
;----------------------------------------------------------------------------- |
align 4 |
syscall_getpixel_WinMap: ; GetPixel WinMap |
cmp ebx, [Screen_Max_X] |
jbe @f |
cmp ecx, [Screen_Max_Y] |
jbe @f |
xor eax, eax |
jmp .store |
;-------------------------------------- |
align 4 |
@@: |
mov eax, [d_width_calc_area + ecx*4] |
add eax, [_WinMapAddress] |
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, [Screen_Max_X] |
inc ecx |
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 |
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 |
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 |
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, [_WinMapAddress] |
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 |
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 |
; eax=1 create thread |
; |
; ebx=thread start |
; ecx=thread stack value |
; |
; on return : eax = pid |
call new_sys_threads |
mov [esp+32], eax |
ret |
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] |
inc ecx |
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] |
inc ecx |
mov edi, BPSLine_calc_area |
cld |
@@: |
stosd |
add eax, [BytesPerScanLine] |
dec ecx |
jnz @r |
ret |
;------------------------------------------------------------------------------ |
align 4 |
set_screen: |
; in: |
; eax - new Screen_Max_X |
; ecx - new BytesPerScanLine |
; edx - new Screen_Max_Y |
cmp eax, [Screen_Max_X] |
jne .set |
cmp edx, [Screen_Max_Y] |
jne .set |
ret |
.set: |
pushfd |
cli |
mov [Screen_Max_X], eax |
mov [Screen_Max_Y], edx |
mov [BytesPerScanLine], 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, [_WinMapAddress] |
mov eax, [_display.width] |
mul [_display.height] |
mov [_WinMapSize], eax |
stdcall kernel_alloc, eax |
mov [_WinMapAddress], 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, [Screen_Max_X] |
mov edx, [Screen_Max_Y] |
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 |
system_shutdown: ; shut down the system |
cmp byte [BOOT_VAR+0x9030], 1 |
jne @F |
ret |
@@: |
call stop_all_services |
push 3 ; stop playing cd |
pop eax |
call sys_cd_audio |
yes_shutdown_param: |
cli |
if ~ defined extended_primary_loader |
mov eax, kernel_file ; load kernel.mnt to 0x7000:0 |
push 12 |
pop esi |
xor ebx, ebx |
or ecx, -1 |
mov edx, OS_BASE+0x70000 |
call fileread |
mov esi, restart_kernel_4000+OS_BASE+0x10000 ; move kernel re-starter to 0x4000:0 |
mov edi, OS_BASE+0x40000 |
mov ecx, 1000 |
rep movsb |
end if |
mov esi, BOOT_VAR ; restore 0x0 - 0xffff |
mov edi, OS_BASE |
mov ecx, 0x10000/4 |
cld |
rep movsd |
call restorefatchain |
call IRQ_mask_all |
if 0 |
mov word [OS_BASE+0x467+0], pr_mode_exit |
mov word [OS_BASE+0x467+2], 0x1000 |
mov al, 0x0F |
out 0x70, al |
mov al, 0x05 |
out 0x71, al |
mov al, 0xFE |
out 0x64, al |
hlt |
jmp $-1 |
else |
cmp byte [OS_BASE + 0x9030], 2 |
jnz no_acpi_power_off |
; scan for RSDP |
; 1) The first 1 Kb of the Extended BIOS Data Area (EBDA). |
movzx eax, word [OS_BASE + 0x40E] |
shl eax, 4 |
jz @f |
mov ecx, 1024/16 |
call scan_rsdp |
jnc .rsdp_found |
@@: |
; 2) The BIOS read-only memory space between 0E0000h and 0FFFFFh. |
mov eax, 0xE0000 |
mov ecx, 0x2000 |
call scan_rsdp |
jc no_acpi_power_off |
.rsdp_found: |
mov esi, [eax+16] ; esi contains physical address of the RSDT |
mov ebp, [ipc_tmp] |
stdcall map_page, ebp, esi, PG_MAP |
lea eax, [esi+1000h] |
lea edx, [ebp+1000h] |
stdcall map_page, edx, eax, PG_MAP |
and esi, 0xFFF |
add esi, ebp |
cmp dword [esi], 'RSDT' |
jnz no_acpi_power_off |
mov ecx, [esi+4] |
sub ecx, 24h |
jbe no_acpi_power_off |
shr ecx, 2 |
add esi, 24h |
.scan_fadt: |
lodsd |
mov ebx, eax |
lea eax, [ebp+2000h] |
stdcall map_page, eax, ebx, PG_MAP |
lea eax, [ebp+3000h] |
add ebx, 0x1000 |
stdcall map_page, eax, ebx, PG_MAP |
and ebx, 0xFFF |
lea ebx, [ebx+ebp+2000h] |
cmp dword [ebx], 'FACP' |
jz .fadt_found |
loop .scan_fadt |
jmp no_acpi_power_off |
.fadt_found: |
; ebx is linear address of FADT |
mov edi, [ebx+40] ; physical address of the DSDT |
lea eax, [ebp+4000h] |
stdcall map_page, eax, edi, PG_MAP |
lea eax, [ebp+5000h] |
lea esi, [edi+0x1000] |
stdcall map_page, eax, esi, PG_MAP |
and esi, 0xFFF |
sub edi, esi |
cmp dword [esi+ebp+4000h], 'DSDT' |
jnz no_acpi_power_off |
mov eax, [esi+ebp+4004h] ; DSDT length |
sub eax, 36+4 |
jbe no_acpi_power_off |
add esi, 36 |
.scan_dsdt: |
cmp dword [esi+ebp+4000h], '_S5_' |
jnz .scan_dsdt_cont |
cmp byte [esi+ebp+4000h+4], 12h ; DefPackage opcode |
jnz .scan_dsdt_cont |
mov dl, [esi+ebp+4000h+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+ebp+4000h+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_power_off |
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_power_off |
inc esi |
mov ch, [esi] |
@@: |
jmp do_acpi_power_off |
.scan_dsdt_cont: |
inc esi |
cmp esi, 0x1000 |
jb @f |
sub esi, 0x1000 |
add edi, 0x1000 |
push eax |
lea eax, [ebp+4000h] |
stdcall map_page, eax, edi, PG_MAP |
push PG_MAP |
lea eax, [edi+1000h] |
push eax |
lea eax, [ebp+5000h] |
push eax |
stdcall map_page |
pop eax |
@@: |
dec eax |
jnz .scan_dsdt |
jmp no_acpi_power_off |
do_acpi_power_off: |
mov edx, [ebx+48] |
test edx, edx |
jz .nosmi |
mov al, [ebx+52] |
out dx, al |
mov edx, [ebx+64] |
@@: |
in ax, dx |
test al, 1 |
jz @b |
.nosmi: |
and cx, 0x0707 |
shl cx, 2 |
or cx, 0x2020 |
mov edx, [ebx+64] |
in ax, dx |
and ax, 203h |
or ah, cl |
out dx, ax |
mov edx, [ebx+68] |
test edx, edx |
jz @f |
in ax, dx |
and ax, 203h |
or ah, ch |
out dx, ax |
@@: |
jmp $ |
no_acpi_power_off: |
mov word [OS_BASE+0x467+0], pr_mode_exit |
mov word [OS_BASE+0x467+2], 0x1000 |
mov al, 0x0F |
out 0x70, al |
mov al, 0x05 |
out 0x71, al |
mov al, 0xFE |
out 0x64, al |
hlt |
jmp $-1 |
scan_rsdp: |
add eax, OS_BASE |
.s: |
cmp dword [eax], 'RSD ' |
jnz .n |
cmp dword [eax+4], 'PTR ' |
jnz .n |
xor edx, edx |
xor esi, esi |
@@: |
add dl, [eax+esi] |
inc esi |
cmp esi, 20 |
jnz @b |
test dl, dl |
jz .ok |
.n: |
add eax, 10h |
loop .s |
stc |
.ok: |
ret |
end if |
include "data32.inc" |
__REV__ = __REV |
uglobals_size = $ - endofcode |
if ~ lang eq sp |
diff16 "end of kernel code",0,$ |
end if |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/network/stack.inc |
---|
0,0 → 1,781 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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 |
MAX_NET_DEVICES = 16 |
ARP_BLOCK = 1 ; true or false |
MIN_EPHEMERAL_PORT = 49152 |
MIN_EPHEMERAL_PORT_N = 0x00C0 ; same in Network byte order (FIXME) |
MAX_EPHEMERAL_PORT = 61000 |
MAX_EPHEMERAL_PORT_N = 0x48EE ; same in Network byte order (FIXME) |
; Ethernet protocol numbers |
ETHER_ARP = 0x0608 |
ETHER_IPv4 = 0x0008 |
ETHER_IPv6 = 0xDD86 |
ETHER_PPP_DISCOVERY = 0x6388 |
ETHER_PPP_SESSION = 0x6488 |
; PPP protocol numbers |
PPP_IPv4 = 0x2100 |
PPP_IPV6 = 0x5780 |
;Protocol family |
AF_UNSPEC = 0 |
AF_LOCAL = 1 |
AF_INET4 = 2 |
AF_INET6 = 10 |
AF_PPP = 777 |
; Internet protocol numbers |
IP_PROTO_IP = 0 |
IP_PROTO_ICMP = 1 |
IP_PROTO_TCP = 6 |
IP_PROTO_UDP = 17 |
; PPP protocol number |
PPP_PROTO_ETHERNET = 666 |
; Socket types |
SOCK_STREAM = 1 |
SOCK_DGRAM = 2 |
SOCK_RAW = 3 |
; 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_BLOCK = 1 shl 10 ; TO BE REMOVED |
SO_NONBLOCK = 1 shl 31 |
; Socket flags for user calls |
MSG_PEEK = 0x02 |
MSG_DONTWAIT = 0x40 |
; Socket level |
SOL_SOCKET = 0 |
; 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 = 0x0100 ; async i/o notify |
SS_ISCONFIRMING = 0x0200 ; deciding to accept connection req |
SS_MORETOCOME = 0x0400 |
SS_BLOCKED = 0x8000 |
SOCKET_MAXDATA = 4096*32 ; must be 4096*(power of 2) where 'power of 2' is at least 8 |
; Network driver types |
NET_TYPE_LOOPBACK = 0 |
NET_TYPE_ETH = 1 |
NET_TYPE_SLIP = 2 |
MAX_backlog = 20 ; maximum backlog for stream sockets |
; Error Codes |
ENOBUFS = 55 |
ECONNREFUSED = 61 |
ECONNRESET = 52 |
ETIMEDOUT = 60 |
ECONNABORTED = 53 |
; 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 |
HWACC_TCP_IPv4 = 1 shl 0 |
struct NET_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 ? ; |
bytes_tx dq ? ; Statistics, updated by the driver |
bytes_rx dq ? ; |
packets_tx dd ? ; |
packets_rx dd ? ; |
state dd ? ; link state (0 = no link) |
hwacc dd ? ; bitmask stating enabled HW accelerations (offload engines) |
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" |
align 4 |
uglobal |
NET_RUNNING dd ? |
NET_DEFAULT dd ? |
NET_DRV_LIST rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; stack_init |
; |
; This function calls all network init procedures |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
stack_init: |
; Init the network drivers list |
xor eax, eax |
mov edi, NET_RUNNING |
mov ecx, (MAX_NET_DEVICES + 2) |
rep stosd |
PPPoE_init |
IPv4_init |
; IPv6_init |
ICMP_init |
ARP_init |
UDP_init |
TCP_init |
SOCKET_init |
mov [net_tmr_count], 0 |
ret |
;----------------------------------------------------------------- |
; |
; stack_handler |
; |
; This function is called in kernel loop |
; |
; IN: / |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
stack_handler: |
cmp [NET_RUNNING], 0 |
je .exit |
; Test for 10ms tick |
mov eax, [timer_ticks] |
cmp eax, [net_10ms] |
je .exit |
mov [net_10ms], eax |
test [net_10ms], 0x0f ; 160ms |
jnz .exit |
TCP_timer_160ms |
test [net_10ms], 0x3f ; 640ms |
jnz .exit |
TCP_timer_640ms |
ARP_decrease_entry_ttls |
IPv4_decrease_fragment_ttls |
.exit: |
ret |
align 4 |
NET_link_changed: |
DEBUGF 1,"NET_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.state] |
align 4 |
NET_send_event: |
DEBUGF 1,"NET_send_event\n" |
; Send event to all applications |
push edi ecx |
mov edi, SLOT_BASE |
mov ecx, [TASK_COUNT] |
.loop: |
add edi, 256 |
or [edi + APPDATA.event_mask], EVENT_NETWORK2 |
loop .loop |
pop ecx edi |
call change_task |
ret |
;----------------------------------------------------------------- |
; |
; NET_add_device: |
; |
; This function is called by the network drivers, |
; to register each running NIC to the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: Device num in eax, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
NET_add_device: |
DEBUGF 1,"NET_Add_Device: %x\n", ebx ;;; TODO: use mutex to lock net device list |
cmp [NET_RUNNING], MAX_NET_DEVICES |
jae .error |
;---------------------------------- |
; Check if device is already listed |
mov eax, ebx |
mov ecx, MAX_NET_DEVICES ; We need to check whole list because a device may be removed without re-organizing list |
mov edi, NET_DRV_LIST |
repne scasd ; See if device is already in the list |
jz .error |
;---------------------------- |
; Find empty slot in the list |
xor eax, eax |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_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_DRV_LIST |
shr eax, 2 |
inc [NET_RUNNING] ; Indicate that one more network device is up and running |
cmp eax, 1 ; If it's the first network device, try to set it as default |
jne @f |
push eax |
call NET_set_default |
pop eax |
@@: |
call NET_send_event |
DEBUGF 1,"Device number: %u\n", eax |
ret |
.error: |
or eax, -1 |
DEBUGF 2,"Adding network device failed\n" |
ret |
;----------------------------------------------------------------- |
; |
; NET_set_default |
; |
; API to set the default interface |
; |
; IN: Device num in eax |
; OUT: Device num in eax, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
NET_set_default: |
DEBUGF 1,"NET_set_default: device=%x\n", eax |
cmp eax, MAX_NET_DEVICES |
jae .error |
cmp [NET_DRV_LIST+eax*4], 0 |
je .error |
mov [NET_DEFAULT], eax |
DEBUGF 1,"NET_set_default: succes\n" |
ret |
.error: |
or eax, -1 |
DEBUGF 1,"NET_set_default: failed\n" |
ret |
;----------------------------------------------------------------- |
; |
; NET_Remove_Device: |
; |
; This function is called by etwork drivers, |
; to unregister network devices from the kernel |
; |
; IN: Pointer to device structure in ebx |
; OUT: eax: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
NET_remove_device: |
cmp [NET_RUNNING], 0 |
je .error |
cmp [NET_DRV_LIST], ebx |
jne @f |
mov [NET_DRV_LIST], 0 |
cmp [NET_RUNNING], 1 |
je @f |
; there are still active devices, find one and make it default |
xor eax, eax |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST |
repe scasd |
je @f |
shr edi, 2 |
dec edi |
mov [NET_DEFAULT], edi |
@@: |
;---------------------------- |
; Find the driver in the list |
mov eax, ebx |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST+4 |
repne scasd |
jnz .error |
;------------------------ |
; Remove it from the list |
xor eax, eax |
mov dword [edi-4], eax |
call NET_send_event |
dec [NET_RUNNING] |
ret |
.error: |
or eax, -1 |
ret |
;----------------------------------------------------------------- |
; |
; NET_ptr_to_num |
; |
; IN: ebx = ptr to device struct |
; OUT: edi = -1 on error, device number otherwise |
; |
;----------------------------------------------------------------- |
align 4 |
NET_ptr_to_num: |
push ecx |
mov ecx, MAX_NET_DEVICES |
mov edi, NET_DRV_LIST |
.loop: |
cmp ebx, [edi] |
jz .found |
add edi, 4 |
dec ecx |
jnz .loop |
; repnz scasd could work too if eax is used instead of ebx! |
or edi, -1 |
pop ecx |
ret |
.found: |
sub edi, NET_DRV_LIST |
shr edi, 2 |
pop ecx |
ret |
;----------------------------------------------------------------- |
; |
; checksum_1 |
; |
; This is the first of two functions needed to calculate a checksum. |
; |
; IN: edx = start offset for semi-checksum |
; esi = pointer to data |
; ecx = data size |
; OUT: edx = semi-checksum |
; |
; |
; Code was optimized by diamond |
; |
;----------------------------------------------------------------- |
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 |
; |
; This function calculates the final ip/tcp/udp checksum for you |
; |
; 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 1,"Checksum: %x\n", dx |
ret |
;---------------------------------------------------------------- |
; |
; System function to work with network devices (75) |
; |
;---------------------------------------------------------------- |
align 4 |
sys_network: ; FIXME: make default device easily accessible |
cmp ebx, -1 |
jne @f |
mov eax, [NET_RUNNING] |
jmp .return |
@@: |
cmp bh, MAX_NET_DEVICES ; Check if device number exists |
jae .doesnt_exist |
mov esi, ebx |
and esi, 0x0000ff00 |
shr esi, 6 |
cmp dword [esi + NET_DRV_LIST], 0 ; check if driver is running |
je .doesnt_exist |
mov eax, [esi + NET_DRV_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 .set_default ; 6 |
.number = ($ - .table) / 4 - 1 |
.get_type: ; 0 = Get device type (ethernet/token ring/...) |
mov eax, [eax + NET_DEVICE.type] |
jmp .return |
.get_dev_name: ; 1 = Get device name |
mov esi, [eax + NET_DEVICE.name] |
mov edi, ecx |
mov ecx, 64/4 ; max length |
rep movsd |
xor eax, eax |
jmp .return |
.reset: ; 2 = Reset the device |
call [eax + NET_DEVICE.reset] |
jmp .return |
.stop: ; 3 = Stop driver for this device |
call [eax + NET_DEVICE.unload] |
jmp .return |
.get_ptr: ; 4 = Get driver pointer |
jmp .return |
.get_drv_name: ; 5 = Get driver name |
xor eax, eax |
jmp .return |
.set_default: ; 6 = Set default device |
call NET_set_default |
jmp .return |
.doesnt_exist: |
mov eax, -1 |
.return: |
mov [esp+32], eax |
ret |
;---------------------------------------------------------------- |
; |
; System function to work with protocols (76) |
; |
;---------------------------------------------------------------- |
align 4 |
sys_protocols: |
cmp bh, MAX_NET_DEVICES ; Check if device number exists |
jae .doesnt_exist |
mov esi, ebx |
and esi, 0x0000ff00 |
shr esi, 6 ; now we have the device num * 4 in esi |
cmp [esi + NET_DRV_LIST], 0 ; check if driver 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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/IPv4.inc |
---|
0,0 → 1,1019 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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$ |
MAX_FRAGMENTS = 64 |
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 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 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 |
align 4 |
uglobal |
IP_LIST rd MAX_NET_DEVICES |
SUBNET_LIST rd MAX_NET_DEVICES |
DNS_LIST rd MAX_NET_DEVICES |
GATEWAY_LIST rd MAX_NET_DEVICES |
BROADCAST_LIST rd MAX_NET_DEVICES |
IP_packets_tx rd MAX_NET_DEVICES |
IP_packets_rx rd MAX_NET_DEVICES |
IP_packets_dumped rd MAX_NET_DEVICES |
FRAGMENT_LIST rb MAX_FRAGMENTS * sizeof.FRAGMENT_slot |
endg |
;----------------------------------------------------------------- |
; |
; IPv4_init |
; |
; This function resets all IP variables |
; |
;----------------------------------------------------------------- |
macro IPv4_init { |
xor eax, eax |
mov edi, IP_LIST |
mov ecx, 7*MAX_NET_DEVICES + (sizeof.FRAGMENT_slot*MAX_FRAGMENTS)/4 |
rep stosd |
} |
;----------------------------------------------------------------- |
; |
; Decrease TimeToLive of all fragment slots |
; |
;----------------------------------------------------------------- |
macro IPv4_decrease_fragment_ttls { |
local .loop, .next |
mov esi, FRAGMENT_LIST |
mov ecx, MAX_FRAGMENTS |
.loop: |
cmp [esi + FRAGMENT_slot.ttl], 0 |
je .next |
dec [esi + FRAGMENT_slot.ttl] |
jz .died |
.next: |
add esi, sizeof.FRAGMENT_slot |
dec ecx |
jnz .loop |
jmp .done |
.died: |
DEBUGF 2,"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: |
; |
; Will check if IPv4 Packet isnt damaged |
; and call appropriate handler. (TCP/UDP/ICMP/..) |
; |
; It will also re-construct fragmented packets |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; pointer to IPv4 header in edx |
; size of IPv4 packet in ecx |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
IPv4_input: ; TODO: add IPv4 raw sockets support |
DEBUGF 2,"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 2,"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 |
;------------------------------- |
; re-calculate the checksum |
IPv4_checksum edx |
jnz .dump ; if checksum isn't valid then dump packet |
DEBUGF 1,"IPv4_input: Checksum ok\n" |
;----------------------------------- |
; Check if destination IP is correct |
call NET_ptr_to_num |
shl edi, 2 |
; check if it matches local ip (Using RFC1122 strong end system model) |
mov eax, [edx + IPv4_header.DestinationAddress] |
cmp eax, [IP_LIST + edi] |
je .ip_ok |
; check for broadcast (IP or (not SUBNET)) |
cmp eax, [BROADCAST_LIST + edi] |
je .ip_ok |
; or a special broadcast (255.255.255.255) |
cmp eax, 0xffffffff |
je .ip_ok |
; maybe it's a multicast (224.0.0.0/4) |
and eax, 0x0fffffff |
cmp eax, 224 |
je .ip_ok |
; or a loopback address (127.0.0.0/8) |
and eax, 0x00ffffff |
cmp eax, 127 |
je .ip_ok |
; or it's just not meant for us.. :( |
DEBUGF 2,"IPv4_input: Destination address does not match!\n" |
jmp .dump |
;------------------------ |
; Now we can update stats |
.ip_ok: |
inc [IP_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 ; |
lea edi, [edx + IPv4_header.SourceAddress] ; make edi ptr to source and dest IPv4 address |
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 |
DEBUGF 2,"IPv4_input: unknown protocol %u\n", al |
.dump: |
DEBUGF 1,"IPv4_input: dumping\n" |
inc [IP_packets_dumped] ; FIXME: use correct interface |
call kernel_free |
add esp, 4 ; pop (balance stack) |
ret |
;--------------------------- |
; Fragmented packet handler |
.has_fragments: |
movzx eax, [edx + IPv4_header.FlagsAndFragmentOffset] |
xchg al, ah |
shl ax, 3 |
DEBUGF 1,"IPv4_input: fragmented packet offset=%u id=%x\n", ax, [edx + IPv4_header.Identification]:4 |
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 1,"IPv4_input: Middle fragment packet received!\n" |
call IPv4_find_fragment_slot |
cmp esi, -1 |
je .dump |
mov [esi + FRAGMENT_slot.ttl], 15 ; Reset the ttl |
mov esi, [esi + FRAGMENT_slot.ptr] |
or edi, -1 |
.find_last_entry: ; The following routine will try to find the last entry |
cmp edi, [esi + 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 + 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 + FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry |
mov [eax + FRAGMENT_entry.NextPtr], -1 |
mov [eax + FRAGMENT_entry.PrevPtr], edi |
mov [eax + FRAGMENT_entry.Owner], ebx |
add esp, 4 |
ret |
;------------------------------------ |
; We have received the first fragment |
.is_first_fragment: |
DEBUGF 1,"IPv4_input: First fragment packet received!\n" |
; try to locate a free slot.. |
mov ecx, MAX_FRAGMENTS |
mov esi, FRAGMENT_LIST |
.find_free_slot: |
cmp word [esi + FRAGMENT_slot.ttl], 0 |
je .found_free_slot |
add esi, sizeof.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 + FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl |
mov ax, [edx + IPv4_header.Identification] |
mov [esi + FRAGMENT_slot.id], ax |
mov eax, [edx + IPv4_header.SourceAddress] |
mov [esi + FRAGMENT_slot.SrcIP], eax |
mov eax, [edx + IPv4_header.DestinationAddress] |
mov [esi + FRAGMENT_slot.DstIP], eax |
pop eax |
mov [esi + FRAGMENT_slot.ptr], eax |
; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure |
mov [eax + FRAGMENT_entry.NextPtr], -1 |
mov [eax + FRAGMENT_entry.PrevPtr], -1 |
mov [eax + FRAGMENT_entry.Owner], ebx |
add esp, 4 ; balance stack and exit |
ret |
;----------------------------------- |
; We have received the last fragment |
.is_last_fragment: |
DEBUGF 1,"IPv4_input: Last fragment packet received!\n" |
call IPv4_find_fragment_slot |
cmp esi, -1 |
je .dump |
mov esi, [esi + 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 + 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.FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length |
xchg cl, ch |
DEBUGF 1,"IPv4_input: Packet size=%u\n", cx |
add ax, cx |
movzx cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length |
and cx, 0x000F |
shl cx, 2 |
DEBUGF 1,"IPv4_input: Header size=%u\n", cx |
sub ax, cx |
mov edi, esi |
mov esi, [esi + FRAGMENT_entry.NextPtr] |
cmp esi, -1 |
jne .count_bytes |
mov esi, [esp+4] |
mov [edi + FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code |
mov [esi + FRAGMENT_entry.NextPtr], -1 |
mov [esi + FRAGMENT_entry.PrevPtr], edi |
mov [esi + FRAGMENT_entry.Owner], ebx |
mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length |
xchg cl, ch |
DEBUGF 1,"IPv4_input: Packet size=%u\n", cx |
add ax, cx |
DEBUGF 1,"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 1,"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.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 1,"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.FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment |
and bx, 0x000F ; |
shl bx, 2 ; |
lea esi, [edx + sizeof.FRAGMENT_entry] ; Set esi to the correct begin of fragment |
movzx ecx, [edx + sizeof.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: |
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 ; Push pointer to fragment onto stack |
mov ebx, [edx + FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet |
mov edx, [edx + FRAGMENT_entry.NextPtr] ; Set edx to the next pointer |
call kernel_free ; free the previous fragment buffer (this uses the value from stack) |
pop 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, 8 |
xchg cl, ch |
push ecx |
push eax |
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 1,"IPv4_input: Destroy fragment slot!\n" |
; TODO! |
jmp .dump |
;----------------------------------------------------------------- |
; |
; 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, MAX_FRAGMENTS |
mov esi, FRAGMENT_LIST |
mov ebx, [edx + IPv4_header.SourceAddress] |
mov edx, [edx + IPv4_header.DestinationAddress] |
.find_slot: |
cmp [esi + FRAGMENT_slot.id], ax |
jne .try_next |
cmp [esi + FRAGMENT_slot.SrcIP], ebx |
jne .try_next |
cmp [esi + FRAGMENT_slot.DstIP], edx |
je .found_slot |
.try_next: |
add esi, sizeof.FRAGMENT_slot |
loop .find_slot |
or esi, -1 |
.found_slot: |
pop edx ecx ebx eax |
ret |
;------------------------------------------------------------------ |
; |
; IPv4_output |
; |
; IN: eax = dest ip |
; ebx = output device ptr/0 for automatic choice |
; ecx = data length |
; edx = source ip |
; di = TTL shl 8 + protocol |
; |
; OUT: eax = pointer to buffer start |
; ebx = pointer to device struct (needed for sending procedure) |
; ecx = unchanged (packet size of embedded data) |
; edx = size of complete buffer |
; edi = pointer to start of data (0 on error) |
; |
;------------------------------------------------------------------ |
align 4 |
IPv4_output: |
DEBUGF 1,"IPv4_output: size=%u\n", ecx |
cmp ecx, 65500 ; Max IPv4 packet size |
ja .too_large |
push ecx eax edx di |
cmp eax, 1 shl 24 + 127 |
je .loopback |
call IPv4_route ; outputs device number in edi, dest ip in eax |
call ARP_IP_to_MAC |
test eax, 0xffff0000 ; error bits |
jnz .arp_error |
push ebx ; push the mac onto the stack |
push ax |
inc [IP_packets_tx + edi] ; update stats |
mov ebx, [NET_DRV_LIST + edi] |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
mov ecx, [esp + 10 + 6] |
add ecx, sizeof.IPv4_header |
mov di, ETHER_IPv4 |
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 |
pop word [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol |
; [edi + IPv4_header.Protocol] |
mov [edi + IPv4_header.HeaderChecksum], 0 |
popd [edi + IPv4_header.SourceAddress] |
popd [edi + IPv4_header.DestinationAddress] |
pop ecx |
IPv4_checksum edi |
add edi, sizeof.IPv4_header |
DEBUGF 2,"IPv4_output: success!\n" |
ret |
.eth_error: |
DEBUGF 2,"IPv4_output: ethernet error\n" |
add esp, 3*4+2+6 |
xor edi, edi |
ret |
.arp_error: |
DEBUGF 2,"IPv4_output: ARP error=%x\n", eax |
add esp, 3*4+2 |
xor edi, edi |
ret |
.too_large: |
DEBUGF 2,"IPv4_output: Packet too large!\n" |
xor edi, edi |
ret |
.loopback: |
mov dword [esp + 2], eax |
add ecx, sizeof.IPv4_header |
mov di, ETHER_IPv4 |
call LOOP_output |
jmp .continue |
;------------------------------------------------------------------ |
; |
; IPv4_output_raw |
; |
; IN: eax = socket ptr |
; ecx = data length |
; esi = data ptr |
; |
; OUT: / |
; |
;------------------------------------------------------------------ |
align 4 |
IPv4_output_raw: |
DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax |
cmp ecx, 1480 ;;;;; FIXME |
ja .too_large |
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 [IP_packets_tx + edi] |
mov ebx, [NET_DRV_LIST + edi] |
lea eax, [ebx + ETH_DEVICE.mac] |
mov edx, esp |
mov ecx, [esp + 6 + 4] |
add ecx, sizeof.IPv4_header |
mov di, ETHER_IPv4 |
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 2,"IPv4_output_raw: device=%x\n", ebx |
call [ebx + NET_DEVICE.transmit] |
ret |
.error: |
add esp, 6 |
.arp_error: |
add esp, 8+4+4 |
.too_large: |
DEBUGF 2,"IPv4_output_raw: Failed\n" |
sub edi, edi |
ret |
;-------------------------------------------------------- |
; |
; |
; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented |
; dword [esp+4] = buffer size |
; esi = pointer to ip header in that buffer |
; ecx = max size of fragments |
; |
; OUT: / |
; |
;-------------------------------------------------------- |
align 4 |
IPv4_fragment: |
DEBUGF 1,"IPv4_fragment\n" |
and ecx, not 111b ; align 4 |
cmp ecx, sizeof.IPv4_header + 8 ; must be able to put at least 8 bytes |
jb .err2 |
push esi ecx |
mov eax, [esi + IPv4_header.DestinationAddress] |
call ARP_IP_to_MAC |
pop ecx esi |
cmp eax, -1 |
jz .err2 |
push ebx |
push ax |
mov ebx, [NET_DRV_LIST] |
lea eax, [ebx + ETH_DEVICE.mac] |
push eax |
push esi ; ptr to ip header |
sub ecx, sizeof.IPv4_header ; substract header size |
push ecx ; max data size |
push dword 0 ; offset |
.new_fragment: |
DEBUGF 1,"Ipv4_fragment: new fragment" |
mov eax, [esp + 3*4] |
lea ebx, [esp + 4*4] |
mov di , ETHER_IPv4 |
call ETH_output |
cmp edi, -1 |
jz .err |
; copy header |
mov esi, [esp + 2*4] |
mov ecx, 5 ; 5 dwords: TODO: use IHL field of the header! |
rep movsd |
; copy data |
mov esi, [esp + 2*4] |
add esi, sizeof.IPv4_header |
add esi, [esp] ; offset |
mov ecx, [esp + 1*4] |
DEBUGF 1,"IPv4_fragment: copying %u bytes\n", ecx |
rep movsb |
; now, correct header |
mov ecx, [esp + 1*4] |
add ecx, sizeof.IPv4_header |
xchg cl, ch |
mov [edi + IPv4_header.TotalLength], cx |
mov ecx, [esp] ; offset |
xchg cl, ch |
; cmp dword[esp + 4*4], 0 ; last fragment?;<<<<<< |
; je .last_fragment |
or cx, 1 shl 2 ; more fragments |
; .last_fragment: |
mov [edi + IPv4_header.FlagsAndFragmentOffset], cx |
mov [edi + IPv4_header.HeaderChecksum], 0 |
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet |
mov ecx, [esp + 1*4] |
push edx eax |
IPv4_checksum edi |
call [ebx + NET_DEVICE.transmit] |
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
mov ecx, [esp+4] |
add [esp], ecx |
mov ecx, [esp+3*4+6+4] ; ptr to begin of buff |
add ecx, [esp+3*4+6+4+4] ; buff size |
sub ecx, [esp+2*4] ; ptr to ip header |
add ecx, [esp] ; offset |
DEBUGF 1,"Ipv4_fragment: %u bytes remaining\n", ecx |
cmp ecx, [esp+1*4] |
jae .new_fragment |
mov [esp+4], ecx ; set fragment size to remaining packet size |
jmp .new_fragment |
.err: |
DEBUGF 1,"Ipv4_fragment: failed\n" |
.done: |
add esp, 12 + 4 + 6 |
.err2: |
DEBUGF 1,"Ipv4_fragment: dumping\n" |
call kernel_free |
add esp, 4 |
ret |
;--------------------------------------------------------------------------- |
; |
; IPv4_route |
; |
; IN: eax = Destination IP |
; OUT: edi = device id * 4 |
; eax = ip of gateway if nescessary, unchanged otherwise |
; |
;--------------------------------------------------------------------------- |
align 4 |
IPv4_route: |
cmp eax, 0xffffffff |
je .broadcast |
xor edi, edi |
mov ecx, MAX_NET_DEVICES |
.loop: |
mov ebx, [IP_LIST+edi] |
and ebx, [SUBNET_LIST+edi] |
jz .next |
mov edx, eax |
and edx, [SUBNET_LIST+edi] |
cmp ebx, edx |
je .found_it |
.next: |
add edi, 4 |
dec ecx |
jnz .loop |
.invalid: |
xor edi, edi ; if none found, use device 0 as default |
mov eax, [GATEWAY_LIST] |
.found_it: |
DEBUGF 1,"IPv4_dest_to_dev: %u\n", edi |
ret |
.broadcast: |
xor edi, edi |
ret |
;--------------------------------------------------------------------------- |
; |
; IPv4_get_frgmnt_num |
; |
; IN: / |
; OUT: fragment number in ax |
; |
;--------------------------------------------------------------------------- |
align 4 |
IPv4_get_frgmnt_num: |
xor ax, ax ;;; TODO: replace this with real code |
ret |
;--------------------------------------------------------------------------- |
; |
; IPv4_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
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, [IP_packets_tx + eax] |
ret |
.packets_rx: |
mov eax, [IP_packets_rx + eax] |
ret |
.read_ip: |
mov eax, [IP_LIST + eax] |
ret |
.write_ip: |
mov [IP_LIST + eax], ecx |
mov edi, eax ; device number, we'll need it for ARP |
; pre-calculate the local broadcast address |
mov ebx, [SUBNET_LIST + eax] |
not ebx |
or ebx, ecx |
mov [BROADCAST_LIST + eax], ebx |
mov eax, ecx |
call ARP_output_request ; now send a gratuitous ARP |
call NET_send_event |
xor eax, eax |
ret |
.read_dns: |
mov eax, [DNS_LIST + eax] |
ret |
.write_dns: |
mov [DNS_LIST + eax], ecx |
call NET_send_event |
xor eax, eax |
ret |
.read_subnet: |
mov eax, [SUBNET_LIST + eax] |
ret |
.write_subnet: |
mov [SUBNET_LIST + eax], ecx |
; pre-calculate the local broadcast address |
mov ebx, [IP_LIST + eax] |
not ecx |
or ecx, ebx |
mov [BROADCAST_LIST + eax], ecx |
call NET_send_event |
xor eax, eax |
ret |
.read_gateway: |
mov eax, [GATEWAY_LIST + eax] |
ret |
.write_gateway: |
mov [GATEWAY_LIST + eax], ecx |
call NET_send_event |
xor eax, eax |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/socket.inc |
---|
0,0 → 1,2285 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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 ? ; INET/LOCAL/.. |
Type dd ? ; RAW/STREAM/DGRAP |
Protocol dd ? ; ICMP/IPv4/ARP/TCP/UDP |
errorcode dd ? |
device dd ? ; driver pointer, socket pointer if it's an LOCAL socket |
options dd ? |
state dd ? |
backlog dw ? ; how many incoming connections that can be queued |
snd_proc dd ? |
rcv_proc dd ? |
ends |
struct IP_SOCKET SOCKET |
LocalIP rd 4 ; network byte order |
RemoteIP rd 4 ; network byte order |
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_force 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 ? ; window minus one |
SND_WL2 dd ? ; |
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 ? |
SND_SSTHRESH dd ? |
;---------------------- |
; Transmit timing stuff |
t_idle dd ? |
t_rtt dd ? |
t_rtseq dd ? |
t_srtt dd ? |
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_retransmission dd ? ; rexmt |
timer_persist dd ? |
timer_keepalive dd ? ; keepalive/syn timeout |
timer_timed_wait dd ? ; also used as 2msl timer |
; extra |
ts_ecr dd ? ; timestamp echo reply |
ts_val dd ? |
seg_next dd ? ; re-assembly queue |
temp_bits db ? |
rb 3 ; align |
ends |
struct UDP_SOCKET IP_SOCKET |
LocalPort dw ? ; network byte order |
RemotePort dw ? ; network byte order |
firstpacket db ? |
ends |
struct ICMP_SOCKET IP_SOCKET |
Identifier dw ? |
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 ? |
buf_ptr dd ? |
data_size dd ? |
ends |
SOCKETBUFFSIZE = 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 = (SOCKETBUFFSIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue) |
uglobal |
net_sockets rd 4 |
last_socket_num dd ? |
last_UDP_port dw ? ; These values give the number of the last used ephemeral port |
last_TCP_port dw ? ; |
endg |
;----------------------------------------------------------------- |
; |
; SOCKET_init |
; |
;----------------------------------------------------------------- |
macro SOCKET_init { |
xor eax, eax |
mov edi, net_sockets |
mov ecx, 5 |
rep stosd |
@@: |
pseudo_random eax |
cmp ax, MIN_EPHEMERAL_PORT |
jb @r |
cmp ax, MAX_EPHEMERAL_PORT |
ja @r |
xchg al, ah |
mov [last_UDP_port], ax |
@@: |
pseudo_random eax |
cmp ax, MIN_EPHEMERAL_PORT |
jb @r |
cmp ax, MAX_EPHEMERAL_PORT |
ja @r |
xchg al, ah |
mov [last_TCP_port], ax |
} |
;----------------------------------------------------------------- |
; |
; Socket API (function 74) |
; |
;----------------------------------------------------------------- |
align 4 |
sys_socket: |
cmp ebx, 255 |
jz SOCKET_debug |
cmp ebx, .number |
ja s_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 |
s_error: |
DEBUGF 2,"SOCKET: error\n" |
mov dword [esp+32], -1 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_open |
; |
; IN: domain in ecx |
; type in edx |
; protocol in esi |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_open: |
DEBUGF 2,"SOCKET_open: domain=%u type=%u protocol=%x ", ecx, edx, esi |
push ecx edx esi |
call SOCKET_alloc |
pop esi edx ecx |
jz s_error |
mov [esp+32], edi ; return socketnumber |
DEBUGF 2,"socknum=%u\n", edi |
; push edx |
; and edx, SO_NONBLOCK |
or [eax + SOCKET.options], SO_NONBLOCK ;edx |
; pop edx |
; and edx, not SO_NONBLOCK |
mov [eax + SOCKET.Domain], ecx |
mov [eax + SOCKET.Type], edx |
mov [eax + SOCKET.Protocol], esi |
cmp ecx, AF_INET4 |
jne .no_inet4 |
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: |
DEBUGF 2,"Unknown socket family/protocol\n" |
ret |
align 4 |
.raw: |
test esi, esi ; IP_PROTO_IP |
jz .ip |
cmp esi, IP_PROTO_ICMP |
je .icmp |
cmp esi, IP_PROTO_UDP |
je .udp |
cmp esi, IP_PROTO_TCP |
je .tcp |
ret |
align 4 |
.udp: |
mov [eax + SOCKET.Protocol], IP_PROTO_UDP |
mov [eax + SOCKET.snd_proc], SOCKET_send_udp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
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_stream |
TCP_init_socket eax |
ret |
align 4 |
.ip: |
mov [eax + SOCKET.snd_proc], SOCKET_send_ip |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
ret |
align 4 |
.icmp: |
mov [eax + SOCKET.snd_proc], SOCKET_send_icmp |
mov [eax + SOCKET.rcv_proc], SOCKET_receive_dgram |
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 |
; |
; IN: socket number in ecx |
; pointer to sockaddr struct in edx |
; length of that struct in esi |
; OUT: 0 on success |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_bind: |
DEBUGF 2,"SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
cmp esi, 2 |
jb s_error |
cmp word [edx], AF_INET4 |
je .af_inet4 |
cmp word [edx], AF_LOCAL |
je .af_local |
jmp s_error |
.af_local: |
; TODO: write code here |
mov dword [esp+32], 0 |
ret |
.af_inet4: |
cmp esi, 6 |
jb s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
jmp s_error |
.tcp: |
.udp: |
mov ebx, [edx + 4] ; First, fill in the IP |
test ebx, ebx ; If IP is 0, use default |
jnz @f |
mov ebx, [NET_DEFAULT] |
mov ebx, [IP_LIST + 4*ebx] |
@@: |
mov [eax + IP_SOCKET.LocalIP], ebx |
mov bx, [edx + 2] ; Now fill in the local port if it's still available |
call SOCKET_check_port |
jz s_error ; ZF is set by socket_check_port, on error |
DEBUGF 1,"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 |
;----------------------------------------------------------------- |
; |
; SOCKET_connect |
; |
; IN: socket number in ecx |
; pointer to sockaddr struct in edx |
; length of that struct in esi |
; OUT: 0 on success |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_connect: |
DEBUGF 2,"SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
cmp esi, 8 |
jb s_error |
cmp word [edx], AF_INET4 |
je .af_inet4 |
jmp s_error |
.af_inet4: |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST] ; FIXME |
pop [eax + IP_SOCKET.LocalIP] |
@@: |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
cmp [eax + SOCKET.Protocol], IP_PROTO_IP |
je .ip |
cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP |
je .ip |
jmp s_error |
align 4 |
.udp: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + UDP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + UDP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + UDP_SOCKET.firstpacket], 0 |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword [esp+32], 0 |
ret |
align 4 |
.tcp: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushw [edx + 2] |
pop [eax + TCP_SOCKET.RemotePort] |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
jne @f |
call SOCKET_find_port |
@@: |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT |
push [TCP_sequence_num] |
add [TCP_sequence_num], 6400 |
pop [eax + TCP_SOCKET.ISS] |
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init |
TCP_sendseqinit eax |
; mov [ebx + TCP_SOCKET.timer_retransmission], ;; todo: create macro to set retransmission timer |
mov ebx, eax |
lea eax, [ebx + STREAM_SOCKET.snd] |
call SOCKET_ring_create |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
mov eax, ebx |
call TCP_output |
;;; TODO: wait for successfull connection if blocking socket |
mov dword [esp+32], 0 |
ret |
align 4 |
.ip: |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
pushd [edx + 4] |
pop [eax + IP_SOCKET.RemoteIP] |
push eax |
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue |
pop eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
mov dword [esp+32], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_listen |
; |
; IN: socket number in ecx |
; backlog in edx |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_listen: |
DEBUGF 2,"SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx |
call SOCKET_num_to_ptr |
jz s_error |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jne s_error |
cmp [eax + TCP_SOCKET.LocalPort], 0 |
je s_error |
cmp [eax + IP_SOCKET.LocalIP], 0 |
jne @f |
push [IP_LIST] |
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 |
;----------------------------------------------------------------- |
; |
; SOCKET_accept |
; |
; IN: socket number in ecx |
; addr in edx |
; addrlen in esi |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_accept: |
DEBUGF 2,"SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi |
call SOCKET_num_to_ptr |
jz s_error |
test [eax + SOCKET.options], SO_ACCEPTCON |
jz s_error |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne s_error |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jne s_error |
.loop: |
get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block |
; Ok, we got a socket ptr |
mov eax, [esi] |
; Change thread ID to that of the current thread |
mov ebx, [TASK_BASE] |
mov ebx, [ebx + TASKDATA.pid] |
mov [eax + SOCKET.TID], ebx |
; Convert it to a socket number |
call SOCKET_ptr_to_num |
jz s_error |
; and return it to caller |
mov [esp+32], eax |
ret |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz s_error |
call SOCKET_block |
jmp .loop |
;----------------------------------------------------------------- |
; |
; SOCKET_close |
; |
; IN: socket number in ecx |
; OUT: eax is socket num, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_close: |
DEBUGF 2,"SOCKET_close: socknum=%u\n", ecx |
call SOCKET_num_to_ptr |
jz s_error |
mov dword [esp+32], 0 ; The socket exists, so we will succeed in closing it. |
.socket: |
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 ; 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: |
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED ; state must be LISTEN, SYN_SENT or CLOSED |
jb .free |
call TCP_usrclosed |
call TCP_output ;;;; Fixme: is this nescessary?? |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_receive |
; |
; IN: socket number in ecx |
; addr to buffer in edx |
; length of buffer in esi |
; flags in edi |
; OUT: eax is number of bytes copied, -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_receive: |
DEBUGF 2,"SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi |
call SOCKET_num_to_ptr |
jz s_error |
jmp [eax + SOCKET.rcv_proc] |
align 4 |
SOCKET_receive_dgram: |
DEBUGF 1,"SOCKET_receive: DGRAM\n" |
mov ebx, esi |
mov edi, edx ; addr to buffer |
.loop: |
get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .block ; destroys esi and ecx |
mov ecx, [esi + socket_queue_entry.data_size] |
DEBUGF 1,"SOCKET_receive: %u bytes data\n", ecx |
cmp ecx, ebx |
ja .too_small |
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 1,"SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi |
mov [esp+32+4], ecx ; return number of bytes copied |
; copy the data |
shr ecx, 1 |
jnc .nb |
movsb |
.nb: |
shr ecx, 1 |
jnc .nw |
movsw |
.nw: |
test ecx, ecx |
jz .nd |
rep movsd |
.nd: |
call kernel_free ; remove the packet |
ret |
.too_small: |
DEBUGF 2,"SOCKET_receive: Buffer too small\n" |
jmp s_error |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz s_error |
call SOCKET_block |
jmp .loop |
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 |
align 4 |
SOCKET_receive_stream: |
DEBUGF 1,"SOCKET_receive: STREAM\n" |
mov ebx, edi |
mov ecx, esi |
mov edi, edx |
xor edx, edx |
test ebx, MSG_DONTWAIT |
jnz .dontwait |
.loop: |
cmp [eax + STREAM_SOCKET.rcv + RING_BUFFER.size], 0 |
je .block |
.dontwait: |
test ebx, MSG_PEEK |
jnz .peek |
add eax, STREAM_SOCKET.rcv |
call SOCKET_ring_read |
call SOCKET_ring_free |
mov [esp+32], ecx ; return number of bytes copied |
ret |
.peek: |
mov ecx, [eax + STREAM_SOCKET.rcv + RING_BUFFER.size] |
mov [esp+32], ecx ; return number of bytes available |
ret |
.block: |
test [eax + SOCKET.options], SO_NONBLOCK |
jnz .return0 |
call SOCKET_block |
jmp .loop |
.return0: |
xor ecx, ecx |
mov [esp+32], ecx |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_send |
; |
; |
; IN: socket number in ecx |
; pointer to data in edx |
; datalength in esi |
; flags in edi |
; OUT: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_send: |
DEBUGF 2,"SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi |
call SOCKET_num_to_ptr |
jz s_error |
mov ecx, esi |
mov esi, edx |
jmp [eax + SOCKET.snd_proc] |
align 4 |
SOCKET_send_udp: |
DEBUGF 1,"SOCKET_send: UDP\n" |
mov [esp+32], ecx |
call UDP_output |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_tcp: |
DEBUGF 1,"SOCKET_send: TCP\n" |
push eax |
add eax, STREAM_SOCKET.snd |
call SOCKET_ring_write |
pop eax |
mov [esp+32], ecx |
call TCP_output |
ret |
align 4 |
SOCKET_send_ip: |
DEBUGF 1,"SOCKET_send: IPv4\n" |
mov [esp+32], ecx |
call IPv4_output_raw |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_icmp: |
DEBUGF 1,"SOCKET_send: ICMP\n" |
mov [esp+32], ecx |
call ICMP_output_raw |
cmp eax, -1 |
je s_error |
ret |
align 4 |
SOCKET_send_pppoe: |
DEBUGF 1,"SOCKET_send: PPPoE\n" |
mov [esp+32], ecx |
mov ebx, [eax + SOCKET.device] |
call PPPoE_discovery_output |
cmp eax, -1 |
je s_error |
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_ |
align 4 |
SOCKET_send_local_: |
DEBUGF 1,"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 s_error |
; 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 |
;----------------------------------------------------------------- |
; |
; SOCKET_get_options |
; |
; IN: ecx = socket number |
; edx = pointer to the options: |
; dd level, optname, optval, optlen |
; OUT: -1 on error |
; |
; 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_*. |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_get_opt: |
DEBUGF 2,"SOCKET_get_opt\n" |
call SOCKET_num_to_ptr |
jz s_error |
cmp dword [edx], IP_PROTO_TCP |
jne s_error |
cmp dword [edx+4], -2 |
je @f |
cmp dword [edx+4], -3 |
jne s_error |
@@: |
; 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 |
;----------------------------------------------------------------- |
; |
; SOCKET_set_options |
; |
; IN: ecx = socket number |
; edx = pointer to the options: |
; dd level, optname, optlen, optval |
; OUT: -1 on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_set_opt: |
DEBUGF 2,"SOCKET_set_opt\n" |
call SOCKET_num_to_ptr |
jz s_error |
cmp dword [edx], SOL_SOCKET |
jne s_error |
cmp dword [edx+4], SO_BINDTODEVICE |
je .bind |
cmp dword [edx+4], SO_BLOCK |
je .block |
jmp s_error |
.bind: |
cmp dword [edx+8], 0 |
je .unbind |
movzx edx, byte [edx + 9] |
cmp edx, MAX_NET_DEVICES |
ja s_error |
mov edx, [NET_DRV_LIST + 4*edx] |
test edx, edx |
jz s_error |
mov [eax + SOCKET.device], edx |
DEBUGF 1,"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 |
.block: |
cmp dword [edx+8], 0 |
je .unblock |
and [eax + SOCKET.options], not SO_NONBLOCK |
mov dword [esp+32], 0 ; success! |
ret |
.unblock: |
or [eax + SOCKET.options], SO_NONBLOCK |
mov dword [esp+32], 0 ; success! |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_pair |
; |
; Allocates a pair of linked LOCAL domain sockets |
; |
; IN: / |
; OUT: eax is socket1 num, -1 on error |
; ebx is socket2 num |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_pair: |
DEBUGF 2,"SOCKET_pair\n" |
call SOCKET_alloc |
jz s_error |
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 |
jz .error |
mov [esp+24], 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 |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
pop eax |
ret |
.error: |
mov eax, ebx |
call SOCKET_free |
jmp s_error |
;----------------------------------------------------------------- |
; |
; SOCKET_debug |
; |
; Copies socket variables to application buffer |
; |
; IN: ecx = socket number |
; edx = pointer to buffer |
; |
; OUT: -1 on error |
;----------------------------------------------------------------- |
align 4 |
SOCKET_debug: |
DEBUGF 1,"SOCKET_debug\n" |
mov edi, edx |
test ecx, ecx |
jz .returnall |
call SOCKET_num_to_ptr |
jz s_error |
mov esi, eax |
mov ecx, SOCKETBUFFSIZE/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], 0 |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_find_port |
; |
; Fills 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 2,"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 (to find out if its a TCP/UDP socket) |
; bx = proposed socket number (network byte order) |
; |
; OUT: ZF = set on error |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_check_port: |
DEBUGF 2,"SOCKET_check_port: " |
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 |
DEBUGF 2,"local port %x already in use\n", bx ; FIXME: find a way to print big endian values with debugf |
ret |
.port_ok: |
DEBUGF 2,"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 |
; |
; Updates a (stateless) socket with received data |
; |
; Note: the mutex should already be set ! |
; |
; IN: eax = socket ptr |
; ecx = data size |
; esi = ptr to data |
; [esp] = ptr to buf |
; [esp + 4] = buf size |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_input: |
DEBUGF 2,"SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx |
mov [esp+4], ecx |
push esi |
mov esi, esp |
add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, SOCKET_input.full |
DEBUGF 1,"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 2,"SOCKET_input: socket %x is full!\n", eax |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
popa |
call kernel_free |
add esp, 8 |
ret |
;-------------------------- |
; |
; eax = ptr to ring struct (just a buffer of the right size) |
; |
align 4 |
SOCKET_ring_create: |
push esi |
mov esi, eax |
push edx |
stdcall create_ring_buffer, SOCKET_MAXDATA, PG_SW |
pop edx |
DEBUGF 1,"SOCKET_ring_created: %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_MAXDATA |
mov [esi + RING_BUFFER.end_ptr], eax |
mov eax, esi |
pop esi |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_ring_write |
; |
; Adds data to a stream socket, and updates write pointer and size |
; |
; 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 1,"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_MAXDATA |
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 2,"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_MAXDATA ; 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 |
push eax ecx |
lea ecx, [eax + RING_BUFFER.mutex] |
call mutex_unlock ; TODO: check what registers this function actually destroys |
pop ecx eax |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_ring_read |
; |
; 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 1,"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 2,"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 1,"SOCKET_ring_read: no data at all!\n" |
xor ecx, ecx |
ret |
.less_data: |
mov ecx, edx |
jmp .copy |
;----------------------------------------------------------------- |
; |
; SOCKET_ring_free |
; |
; Free's some bytes from the ringbuffer |
; |
; IN: eax = ptr to ring struct |
; ecx = data size |
; |
; OUT: ecx = number of bytes free-ed |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_ring_free: |
DEBUGF 1,"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_MAXDATA |
@@: |
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 1,"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 |
; |
; Suspends the thread attached to a socket |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_block: |
DEBUGF 1,"SOCKET_block: %x\n", 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], 1 ; Suspended |
; Remember the thread ID so we can wake it up again |
mov edx, [edx + TASKDATA.pid] |
DEBUGF 1,"SOCKET_block: suspending thread: %u\n", edx |
mov [eax + SOCKET.TID], edx |
pop edx |
call change_task |
popf |
DEBUGF 1,"SOCKET_block: continueing\n" |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_notify |
; |
; notify's the owner of a socket that something happened |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_notify: |
DEBUGF 1,"SOCKET_notify: %x\n", eax |
call SOCKET_check |
jz .error |
test [eax + SOCKET.state], SS_BLOCKED |
jnz .unblock |
test [eax + SOCKET.options], SO_NONBLOCK |
jz .error |
push eax ecx esi |
; socket exists and is of non blocking type. |
; We'll try to flag an event to the thread |
mov eax, [eax + SOCKET.TID] |
test eax, eax |
jz .done |
mov ecx, 1 |
mov esi, TASK_DATA + TASKDATA.pid |
.next_pid: |
cmp [esi], eax |
je .found_pid |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next_pid |
; PID not found, TODO: close socket! |
jmp .done |
.found_pid: |
shl ecx, 8 |
or [ecx + SLOT_BASE + APPDATA.event_mask], EVENT_NETWORK |
mov [check_idle_semaphore], 200 ; What does this mean?? |
DEBUGF 1,"SOCKET_notify: Raised a network event!\n" |
jmp .done |
.unblock: |
push eax ecx esi |
; Clear the 'socket is blocked' flag |
and [eax + SOCKET.state], not SS_BLOCKED |
; Find the thread's TASK_DATA |
mov eax, [eax + SOCKET.TID] |
test eax, eax |
jz .error |
xor ecx, ecx |
inc ecx |
mov esi, TASK_DATA |
.next: |
cmp [esi + TASKDATA.pid], eax |
je .found |
inc ecx |
add esi, 0x20 |
cmp ecx, [TASK_COUNT] |
jbe .next |
jmp .error |
.found: |
; Run the thread |
mov [esi + TASKDATA.state], 0 ; Running |
DEBUGF 1,"SOCKET_notify: Unblocked socket!\n" |
.done: |
pop esi ecx eax |
.error: |
ret |
;-------------------------------------------------------------------- |
; |
; SOCKET_alloc |
; |
; Allocate memory for socket data and put new socket into the list |
; Newly created socket is initialized with calling PID and number and |
; put into beginning of list (which is a fastest way). |
; |
; IN: / |
; OUT: eax = 0 on error, socket ptr otherwise |
; edi = socket number |
; ZF = cleared on error |
; |
;-------------------------------------------------------------------- |
align 4 |
SOCKET_alloc: |
push ebx |
stdcall kernel_alloc, SOCKETBUFFSIZE |
DEBUGF 1, "SOCKET_alloc: ptr=%x\n", eax |
or eax, eax |
jz .exit |
; zero-initialize allocated memory |
push eax |
mov edi, eax |
mov ecx, SOCKETBUFFSIZE / 4 |
xor eax, eax |
rep stosd |
pop eax |
; set send-and receive procedures to return -1 |
mov [eax + SOCKET.snd_proc], s_error |
mov [eax + SOCKET.rcv_proc], s_error |
; 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 1, "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 |
or eax, eax ; used to clear zero flag |
.exit: |
pop ebx |
ret |
;---------------------------------------------------- |
; |
; SOCKET_free |
; |
; Free socket data memory and remove socket from the list |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;---------------------------------------------------- |
align 4 |
SOCKET_free: |
DEBUGF 1, "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.Domain], AF_INET4 |
jnz .no_tcp |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jnz .no_tcp |
mov ebx, eax |
stdcall kernel_free, [ebx + STREAM_SOCKET.rcv.start_ptr] |
stdcall kernel_free, [ebx + STREAM_SOCKET.snd.start_ptr] |
mov eax, ebx |
.no_tcp: |
push eax ; this will be passed to kernel_free |
mov ebx, [eax + SOCKET.NextPtr] |
mov eax, [eax + SOCKET.PrevPtr] |
DEBUGF 1, "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 1, "SOCKET_free: success!\n" |
.error: |
ret |
;------------------------------------ |
; |
; SOCKET_fork |
; |
; Create a child socket |
; |
; IN: socket nr in ebx |
; OUT: child socket nr in eax |
; |
;----------------------------------- |
align 4 |
SOCKET_fork: |
DEBUGF 1,"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 |
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, and the 2 pointers at beginning of socket |
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 |
ret |
.fail2: |
add esp, 4+4+4 |
.fail: |
DEBUGF 1,"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 = 0 on error, socket ptr otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_num_to_ptr: |
DEBUGF 1,"SOCKET_num_to_ptr: num=%u ", ecx |
mov eax, net_sockets |
.next_socket: |
mov eax, [eax + SOCKET.NextPtr] |
or eax, eax |
jz .error |
cmp [eax + SOCKET.Number], ecx |
jne .next_socket |
test eax, eax |
DEBUGF 1,"ptr=%x\n", eax |
ret |
.error: |
DEBUGF 1,"not found\n", eax |
ret |
;--------------------------------------------------- |
; |
; SOCKET_ptr_to_num |
; |
; Get socket number by its address |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, socket num otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_ptr_to_num: |
DEBUGF 1,"SOCKET_ptr_to_num: ptr=%x ", eax |
call SOCKET_check |
jz .error |
mov eax, [eax + SOCKET.Number] |
DEBUGF 1,"num=%u\n", eax |
ret |
.error: |
DEBUGF 1,"not found\n", eax |
ret |
;--------------------------------------------------- |
; |
; SOCKET_check |
; |
; checks if the given value is really a socket ptr |
; |
; IN: eax = socket ptr |
; OUT: eax = 0 on error, unchanged otherwise |
; ZF = set on error |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check: |
DEBUGF 1,"SOCKET_check: %x\n", eax |
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 |
;--------------------------------------------------- |
; |
; SOCKET_check_owner |
; |
; checks if the caller application owns the socket |
; |
; IN: eax = socket ptr |
; OUT: ZF = true/false |
; |
;--------------------------------------------------- |
align 4 |
SOCKET_check_owner: |
DEBUGF 1,"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 |
; |
; IN: edx = pid |
; OUT: / |
; |
;------------------------------------------------------ |
align 4 |
SOCKET_process_end: |
DEBUGF 1, "SOCKET_process_end: %x\n", edx |
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 1, "SOCKET_process_end: killing socket %x\n", ebx |
mov [ebx + SOCKET.PID], 0 |
mov eax, ebx |
mov ebx, [ebx + SOCKET.NextPtr] |
pusha |
call SOCKET_close.socket |
popa |
jmp .next_socket_test |
.done: |
pop ebx |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_is_connecting |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_is_connecting: |
DEBUGF 1,"SOCKET_is_connecting: %x\n", eax |
and [eax + SOCKET.options], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.options], SS_ISCONNECTING |
jmp SOCKET_notify |
;----------------------------------------------------------------- |
; |
; SOCKET_is_connected |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_is_connected: |
DEBUGF 1,"SOCKET_is_connected: %x\n", eax |
and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING) |
or [eax + SOCKET.options], SS_ISCONNECTED |
jmp SOCKET_notify |
;----------------------------------------------------------------- |
; |
; SOCKET_is_disconnecting |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_is_disconnecting: |
DEBUGF 1,"SOCKET_is_disconnecting: %x\n", eax |
and [eax + SOCKET.options], not (SS_ISCONNECTING) |
or [eax + SOCKET.options], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE |
jmp SOCKET_notify |
;----------------------------------------------------------------- |
; |
; SOCKET_is_disconnected |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_is_disconnected: |
DEBUGF 1,"SOCKET_is_disconnected: %x\n", eax |
and [eax + SOCKET.options], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING) |
or [eax + SOCKET.options], SS_CANTRCVMORE + SS_CANTSENDMORE |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
je .tcp |
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP |
je .udp |
jmp SOCKET_notify |
.tcp: |
.udp: |
mov [eax + UDP_SOCKET.LocalPort], 0 ; UDP and TCP structs store localport at the same offset |
mov [eax + UDP_SOCKET.RemotePort], 0 |
jmp SOCKET_notify |
;----------------------------------------------------------------- |
; |
; SOCKET_cant_recv_more |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_cant_recv_more: |
DEBUGF 1,"SOCKET_cant_recv_more: %x\n", eax |
or [eax + SOCKET.options], SS_CANTRCVMORE |
ret |
;----------------------------------------------------------------- |
; |
; SOCKET_cant_send_more |
; |
; IN: eax = socket ptr |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
SOCKET_cant_send_more: |
DEBUGF 1,"SOCKET_cant_send_more: %x\n", eax |
or [eax + SOCKET.options], SS_CANTSENDMORE |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/tcp_subr.inc |
---|
0,0 → 1,546 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 ;;;; 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 |
mov [ptr + TCP_SOCKET.RCV_NXT], edi |
mov [ptr + TCP_SOCKET.RCV_ADV], edi |
pop edi |
} |
macro TCP_init_socket socket { |
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 |
} |
;--------------------------- |
; |
; TCP_pull_out_of_band |
; |
; IN: eax = |
; ebx = socket ptr |
; edx = tcp packet ptr |
; |
; OUT: / |
; |
;--------------------------- |
align 4 |
TCP_pull_out_of_band: |
DEBUGF 1,"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: |
DEBUGF 1,"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 |
call TCP_output |
;;; TODO: update stats |
jmp TCP_close |
.no_syn_received: |
;;; TODO: update stats |
;;; TODO: check if error code is "Connection timed out' and handle accordingly |
mov [eax + SOCKET.errorcode], ebx |
;------------------------- |
; |
; TCP_close |
; |
; IN: eax = socket ptr |
; OUT: eax = socket ptr |
; |
;------------------------- |
align 4 |
TCP_close: |
DEBUGF 1,"TCP_close: %x\n", eax |
;;; TODO: update RTT and mean deviation |
;;; TODO: update slow start threshold |
call SOCKET_is_disconnected |
call SOCKET_free |
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 1,"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_TIMED_WAIT |
;--------------------------------------- |
; |
; The fast way to send an ACK/RST/keepalive segment |
; |
; TCP_respond |
; |
; IN: ebx = socket ptr |
; cl = flags |
; |
;-------------------------------------- |
align 4 |
TCP_respond: |
DEBUGF 1,"TCP_respond_socket: socket=%x flags=%x\n", ebx, cl |
;--------------------- |
; Create the IP packet |
push cx ebx |
mov eax, [ebx + IP_SOCKET.RemoteIP] |
mov edx, [ebx + IP_SOCKET.LocalIP] |
mov ecx, sizeof.TCP_header |
mov di, IP_PROTO_TCP shl 8 + 128 |
call IPv4_output |
test edi, edi |
jz .error |
pop esi cx |
push edx 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 ax, [esi + TCP_SOCKET.RCV_WND] |
; rol ax, 8 |
mov ax, 0x00a0 ;;;;;;; FIXME |
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] |
ret |
.error: |
DEBUGF 1,"TCP_respond_socket: failed\n" |
add esp, 2 + 4 |
ret |
;------------------------- |
; TCP_respond_segment: |
; |
; IN: edx = segment ptr (a previously received segment) |
; edi = ptr to dest and src IPv4 addresses |
; cl = flags |
align 4 |
TCP_respond_segment: |
DEBUGF 1,"TCP_respond_segment: frame=%x flags=%x\n", edx, cl |
;--------------------- |
; Create the IP packet |
push cx edx |
mov ebx, [edi + 4] |
mov eax, [edi] |
mov ecx, sizeof.TCP_header |
mov di, IP_PROTO_TCP shl 8 + 128 |
call IPv4_output |
jz .error |
pop esi cx |
push edx 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] |
ret |
.error: |
DEBUGF 1,"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, value |
jmp .done |
.max: |
mov timer, value |
jmp .done |
.done: |
} |
align 4 |
TCP_set_persist: |
DEBUGF 1,"TCP_set_persist\n" |
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive |
cmp [eax + TCP_SOCKET.timer_retransmission], 0 |
ja @f |
; 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 |
pop ebx |
cmp [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift |
jae @f |
inc [eax + TCP_SOCKET.t_rxtshift] |
@@: |
ret |
; eax = rtt |
; ebx = socket ptr |
align 4 |
TCP_xmit_timer: |
DEBUGF 1,"TCP_xmit_timer: socket=%x rtt=%d0ms\n", ebx, eax |
;TODO: update stats |
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 |
; eax = max segment size |
; ebx = socket ptr |
align 4 |
TCP_mss: |
cmp eax, 1420 ; FIXME |
jbe @f |
mov eax, 1420 |
@@: |
mov [ebx + TCP_SOCKET.t_maxseg], eax |
ret |
; ebx = socket ptr |
; edx = segment ptr |
align 4 |
TCP_reassemble: |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/tcp_input.inc |
---|
0,0 → 1,1664 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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_input: |
; |
; Add a segment to the incoming TCP queue |
; |
; IN: [esp] = ptr to buffer |
; [esp+4] = buffer size (dont care) |
; ebx = ptr to device struct |
; ecx = segment size |
; esi = ptr to TCP segment |
; edi = ptr to ipv4 source address, followed by ipv4 dest address |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
TCP_input: |
; record the current time |
mov eax, [timer_ticks] ; in 1/100 seconds |
mov [esp + 4], eax |
push ebx ecx esi edi ; mind the order |
mov esi, esp |
pushf |
cli |
add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail |
popf |
add esp, sizeof.TCP_queue_entry |
mov [check_idle_semaphore], 5 |
xor edx, edx |
mov eax, [TCP_input_event] |
mov ebx, [eax + EVENT.id] |
xor esi, esi |
call raise_event |
ret |
.fail: |
popf |
DEBUGF 2, "TCP incoming queue is full, discarding packet!\n" |
inc [TCP_segments_missed] ; FIXME: use correct interface |
add esp, sizeof.TCP_queue_entry - 8 |
call kernel_free |
add esp, 4 |
ret |
align 4 |
TCP_process_input: |
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] |
push [esi + TCP_queue_entry.buffer_ptr] |
mov ebx, [esi + TCP_queue_entry.device_ptr] |
mov ecx, [esi + TCP_queue_entry.segment_size] |
mov edi, [esi + TCP_queue_entry.ip_ptr] ; ptr to ipv4 source address, followed by ipv4 destination address |
mov esi, [esi + TCP_queue_entry.segment_ptr] ; change esi last |
DEBUGF 1,"TCP_input: size=%u time=%d\n", ecx, [timer_ticks] |
mov edx, esi |
cmp ebx, LOOPBACK_DEVICE |
je .checksum_ok |
; re-calculate the checksum (if not already done by hw) |
; test [ebx + NET_DEVICE.hwacc], HWACC_TCP_IPv4_IN |
; jnz .checksum_ok |
push ecx esi |
pushw [esi + TCP_header.Checksum] |
mov [esi + TCP_header.Checksum], 0 |
TCP_checksum (edi), (edi+4) |
pop cx ; previous checksum |
cmp cx, dx |
pop edx ecx |
jne .drop_no_socket |
.checksum_ok: |
; Verify the data offset |
and [edx + TCP_header.DataOffset], 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header) |
shr [edx + TCP_header.DataOffset], 2 |
cmp [edx + TCP_header.DataOffset], 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 |
movzx eax, [edx + TCP_header.DataOffset] |
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 1,"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: |
mov ebx, net_sockets |
mov si, [edx + TCP_header.DestinationPort] |
.socket_loop: |
mov ebx, [ebx + SOCKET.NextPtr] |
or ebx, ebx |
jz .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 source address |
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 |
DEBUGF 1,"TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2 |
;------------- |
; update stats |
inc [TCP_segments_rx] ; FIXME: correct interface? |
;---------------------------- |
; 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 1,"TCP_input: socket locked\n" |
;--------------------------- |
; disable all temporary bits |
mov [ebx + TCP_SOCKET.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 |
;--------------------------------------- |
; Are we accepting incoming connections? |
test [ebx + SOCKET.options], SO_ACCEPTCON |
jz .no_accept |
DEBUGF 1,"TCP_input: Accepting new connection\n" |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
push ecx edx esi edi ;;; |
call SOCKET_fork |
pop edi esi edx ecx |
test eax, eax |
jz .drop_no_socket |
mov ebx, eax |
mov [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET ;;; FIXME: should we take over bits from previous socket? |
push dword [edi + 4] ; Ipv4 destination addres |
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 |
;-------------------- |
; Process TCP options |
push ecx |
movzx ecx, [edx + TCP_header.DataOffset] |
cmp ecx, sizeof.TCP_header ; Does header contain any options? |
je .no_options |
DEBUGF 1,"TCP_input: Segment has options\n" |
;;; 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 |
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 1,"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 |
lodsw |
rol ax, 8 |
DEBUGF 1,"TCP_input: Maxseg=%u\n", ax |
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 1,"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 1,"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 1,"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 |
mov [ebx + TCP_SOCKET.ts_val], eax |
lodsd ; timestamp echo reply |
mov [ebx + TCP_SOCKET.ts_ecr], eax |
or [ebx + TCP_SOCKET.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] |
jge .no_paws |
DEBUGF 1,"TCP_input: PAWS: detected an old segment\n" |
mov eax, [esp+4+4] ; tcp_now |
sub eax, [ebx + TCP_SOCKET.ts_recent_age] |
pop ecx |
cmp eax, TCP_PAWS_IDLE |
jle .drop_after_ack ; TODO: update stats |
push ecx |
mov [ebx + TCP_SOCKET.ts_recent], 0 ; timestamp was invalid, fix it. |
.no_paws: |
jmp .opt_loop |
.no_options: |
pop ecx |
;----------------------------------------------------------------------- |
; Time to do some header prediction (Original Principle by 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 1,"TCP_input: Header prediction: we are sender\n" |
;--------------------------------- |
; Packet is a pure ACK, process it |
; 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 [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP |
jz .no_timestamp_rtt |
mov eax, [esp + 4] ; timestamp when this segment was received |
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 |
mov [ebx + TCP_SOCKET.timer_retransmission], 0 |
; 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 (seg_next equals tp). |
;;; TODO |
; jnz .not_uni_xfer |
; Complete processing of received data |
DEBUGF 1,"TCP_input: Header prediction: we are receiving %u bytes\n", ecx |
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied |
movzx esi, [edx + TCP_header.DataOffset] |
add esi, edx |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_write ; Add the data to the socket buffer |
mov eax, ebx |
call SOCKET_notify |
or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag |
jmp .drop |
;-------------------------------------------------- |
; Header prediction failed, do it the slow way |
.not_uni_xfer: |
DEBUGF 1,"TCP_input: Header prediction failed\n" |
; Calculate receive window size |
push edx |
mov eax, SOCKETBUFFSIZE |
sub eax, [ebx + STREAM_SOCKET.rcv.size] |
mov edx, [ebx + TCP_SOCKET.RCV_ADV] |
sub edx, [ebx + TCP_SOCKET.RCV_NXT] |
cmp eax, edx |
jg @f |
mov eax, edx |
@@: |
DEBUGF 1,"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 .LISTEN |
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT |
je .SYN_SENT |
;---------------------------- |
; trim any data not in window |
; check for duplicate data at beginning of segment (635) |
mov eax, [ebx + TCP_SOCKET.RCV_NXT] |
sub eax, [edx + TCP_header.SequenceNumber] |
jle .no_duplicate |
DEBUGF 1,"TCP_input: %u bytes duplicate data!\n", eax |
test [edx + TCP_header.Flags], TH_SYN |
jz .no_dup_syn |
DEBUGF 1,"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 (646) |
cmp eax, ecx ; eax holds number of bytes to drop, ecx is data size |
jb .duplicate |
jnz @f |
test [edx + TCP_header.Flags], TH_FIN |
jnz .duplicate |
@@: |
; 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 and resynchronize and drop any data. |
; But keep on processing for RST or ACK |
DEBUGF 1, "616\n" |
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW |
mov eax, ecx |
;TODO: update stats |
;----------------------------------------------- |
; Remove duplicate data and update urgent offset |
.duplicate: |
;;; TODO: 677 |
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 |
@@: |
;-------------------------------------------------- |
; Handle data that arrives after process terminates (687) |
.no_duplicate: |
cmp [ebx + SOCKET.PID], 0 |
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 |
;;;TODO: update stats |
jmp .respond_seg_reset |
;---------------------------------------- |
; Remove data beyond right edge of window (700-736) |
.not_terminated: |
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 1,"%d bytes beyond right edge of window\n", eax |
;;; TODO: update stats |
cmp eax, ecx |
jl .dont_drop_all |
; 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_TIMED_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 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 eax, [edx + TCP_header.SequenceNumber] |
cmp eax, [ebx + TCP_SOCKET.RCV_NXT] |
jne .drop_after_ack |
DEBUGF 1, "690\n" |
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW |
;;; TODO: update stats |
jmp .no_excess_data |
.dont_drop_all: |
;;; TODO: update stats |
;;; TODO: 733 |
sub ecx, eax |
and [ebx + TCP_SOCKET.t_flags], not (TH_PUSH or TH_FIN) |
.no_excess_data: |
;----------------- |
; Record timestamp (737-746) |
; If last ACK falls within this segments sequence numbers, record its timestamp |
test [ebx + TCP_SOCKET.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 [ebx + 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 1,"Recording timestamp\n" |
mov eax, [esp + 4] ; tcp_now |
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 flags |
test [edx + TCP_header.Flags], TH_RST |
jz .no_rst |
DEBUGF 1,"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_TIMED_WAIT |
.econnrefused: |
DEBUGF 1,"TCP_input: Connection refused\n" |
mov [ebx + SOCKET.errorcode], ECONNREFUSED |
jmp .close |
.econnreset: |
DEBUGF 1,"TCP_input: Connection reset\n" |
mov [ebx + SOCKET.errorcode], ECONNRESET |
.close: |
DEBUGF 1,"TCP_input: Closing connection\n" |
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED |
;;; TODO: update stats (tcp drops) |
mov eax, ebx |
call TCP_close |
jmp .drop_no_socket |
.rst_close: |
DEBUGF 1,"TCP_input: Closing with reset\n" |
mov eax, ebx |
call TCP_close |
jmp .drop_no_socket |
.no_rst: |
;-------------------------------------- |
; handle SYN-full and ACK-less segments |
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: |
;--------------- |
; ACK processing |
test [edx + TCP_header.Flags], TH_ACK |
jz .drop |
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 1,"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 |
;;; TODO: update stats |
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] |
@@: |
;;; TODO: call TCP_reassemble |
mov eax, [edx + TCP_header.SequenceNumber] |
dec eax |
mov [ebx + TCP_SOCKET.SND_WL1], eax |
.no_syn_rcv: |
;------------------------- |
; check for duplicate ACKs |
mov eax, [edx + TCP_header.AckNumber] |
cmp eax, [ebx + TCP_SOCKET.SND_UNA] |
ja .not_dup_ack |
test ecx, ecx |
jnz .reset_dupacks |
mov eax, dword [edx + TCP_header.Window] |
cmp eax, [ebx + TCP_SOCKET.SND_WND] |
jne .reset_dupacks |
DEBUGF 1,"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. |
cmp [ebx + TCP_SOCKET.timer_retransmission], 0 ;;;; FIXME |
jg @f |
mov eax, [edx + TCP_header.AckNumber] |
cmp eax, [ebx + TCP_SOCKET.SND_UNA] |
je .dup_ack |
@@: |
mov [ebx + TCP_SOCKET.t_dupacks], 0 |
jmp .not_dup_ack |
.dup_ack: |
inc [ebx + TCP_SOCKET.t_dupacks] |
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh |
jne .no_re_xmit |
push [ebx + TCP_SOCKET.SND_NXT] ; >>>> |
mov eax, [ebx + TCP_SOCKET.SND_WND] |
cmp eax, [ebx + TCP_SOCKET.SND_CWND] |
cmova 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 |
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; 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 |
.no_re_xmit: |
jbe .not_dup_ack |
DEBUGF 1,"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 |
mov eax, [esp] |
call TCP_output |
; Lock the socket again |
mov ecx, [esp] |
add ecx, SOCKET.mutex |
call mutex_lock |
pop ebx |
jmp .drop |
.not_dup_ack: |
;------------------------------------------------- |
; 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 |
;;; TODO: update stats |
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 |
;;; TODO: update stats |
DEBUGF 1,"TCP_input: acceptable ACK for %u bytes\n", edi |
;------------------------------------------ |
; RTT measurements and retransmission timer (912-926) |
; If we have a timestamp, update smoothed RTT |
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_TIMESTAMP |
jz .timestamp_not_present |
mov eax, [esp+4] |
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 |
mov [ebx + TCP_SOCKET.timer_retransmission], 0 |
or [ebx + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT |
jmp .no_restart |
.more_data: |
cmp [ebx + TCP_SOCKET.timer_persist], 0 |
jne .no_restart |
mov eax, [ebx + TCP_SOCKET.t_rxtcur] |
mov [ebx + TCP_SOCKET.timer_retransmission], eax |
.no_restart: |
;------------------------------------------- |
; Open congestion window in response to ACKs |
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 |
div esi |
pop edx |
shr edx, 3 |
add eax, edx |
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 |
cmova esi, eax |
mov [ebx + TCP_SOCKET.SND_CWND], esi |
;------------------------------------------ |
; Remove acknowledged data from send buffer |
cmp edi, [ebx + STREAM_SOCKET.snd.size] |
jbe .finiacked |
push ecx edx ebx |
mov ecx, [ebx + STREAM_SOCKET.snd.size] |
lea eax, [ebx + STREAM_SOCKET.snd] |
sub [ebx + TCP_SOCKET.SND_WND], ecx |
call SOCKET_ring_free |
pop ebx edx ecx |
DEBUGF 1,"TCP_input: our FIN is acked\n" |
stc |
jmp .wakeup |
.finiacked: |
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 |
DEBUGF 1,"TCP_input: our FIN is not acked\n" |
clc |
;---------------------------------------- |
; Wake up process waiting on send buffer |
.wakeup: |
pushf ; Keep the flags (Carry flag) |
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 |
@@: |
popf |
; General ACK handling complete |
; Now do the state-specific ones |
; Carry flag is set when our FIN is acked |
mov eax, [ebx + TCP_SOCKET.t_state] |
jmp dword [eax*4 + .ACK_sw_list] |
.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: |
jnc .ack_processed |
test [ebx + SOCKET.state], SS_CANTRCVMORE |
jnz @f |
mov eax, ebx |
call SOCKET_is_disconnected |
mov [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle |
@@: |
mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2 |
jmp .ack_processed |
.ack_c: |
jnc .ack_processed |
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT |
mov eax, ebx |
call TCP_cancel_timers |
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL |
mov eax, ebx |
call SOCKET_is_disconnected |
jmp .ack_processed |
.ack_la: |
jnc .ack_processed |
mov eax, ebx |
call TCP_disconnect |
jmp .drop |
.ack_tw: |
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL |
jmp .drop_after_ack |
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter |
mov [ebx + TCP_SOCKET.t_dupacks], 0 |
jmp .ack_processed |
;------- |
; LISTEN |
align 4 |
.LISTEN: |
DEBUGF 1,"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 |
;;; TODO: check if it's a broadcast or multicast, and drop if so |
push dword [edi] ; Ipv4 source addres |
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], 64000 / 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 |
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW |
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro |
lea eax, [ebx + STREAM_SOCKET.snd] |
call SOCKET_ring_create |
lea eax, [ebx + STREAM_SOCKET.rcv] |
call SOCKET_ring_create |
and [ebx + TCP_SOCKET.temp_bits], not TCP_BIT_DROPSOCKET |
;;; call SOCKET_notify_owner |
jmp .trim_then_step6 |
;------------ |
; Active Open |
align 4 |
.SYN_SENT: |
DEBUGF 1,"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 |
@@: |
test [edx + TCP_header.Flags], TH_SYN |
jz .drop |
; at this point, segment seems to be valid |
test [edx + TCP_header.Flags], TH_ACK |
jz .no_syn_ack |
; now, process received SYN in response to an active open |
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 |
@@: |
.no_syn_ack: |
mov [ebx + TCP_SOCKET.timer_retransmission], 0 ; disable retransmission |
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 1,"TCP_input: active open\n" |
;;; TODO: update stats |
; set socket state to connected |
mov [ebx + SOCKET.state], SS_ISCONNECTED |
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 |
mov eax, [ebx + TCP_SOCKET.t_rtt] |
test eax, eax |
je .trim_then_step6 |
call TCP_xmit_timer |
jmp .trim_then_step6 |
.simultaneous_open: |
DEBUGF 1,"TCP_input: simultaneous open\n" |
; We have received a syn but no ACK, so we are having a simultaneous open.. |
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED |
;------------------------------------- |
; Common processing for receipt of SYN |
.trim_then_step6: |
inc [edx + TCP_header.SequenceNumber] |
;;; TODO: Drop any received data that follows receive window (590) |
mov eax, [edx + TCP_header.SequenceNumber] |
mov [ebx + TCP_SOCKET.RCV_UP], eax |
dec eax |
mov [ebx + TCP_SOCKET.SND_WL1], eax |
;------- |
; step 6 |
.ack_processed: |
DEBUGF 1,"TCP_input: ACK processed\n" |
;---------------------------------------------- |
; check if we need to update window information |
test [edx + TCP_header.Flags], TH_ACK |
jz .no_window_update |
mov eax, [ebx + TCP_SOCKET.SND_WL1] |
cmp eax, [edx + TCP_header.SequenceNumber] |
jb .update_window |
ja @f |
mov eax, [ebx + TCP_SOCKET.SND_WL2] |
cmp eax, [edx + TCP_header.AckNumber] |
jb .update_window |
ja .no_window_update |
@@: |
mov eax, dword [edx + TCP_header.Window] |
cmp eax, [ebx + TCP_SOCKET.SND_WND] |
jbe .no_window_update |
.update_window: |
;;; TODO: update stats (Keep track of pure window updates) |
mov eax, dword [edx + TCP_header.Window] |
cmp eax, [ebx + TCP_SOCKET.max_sndwnd] |
jbe @f |
mov [ebx + TCP_SOCKET.max_sndwnd], eax |
@@: |
mov [ebx + TCP_SOCKET.SND_WND], eax |
DEBUGF 1,"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 [ebx + TCP_SOCKET.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_TIMED_WAIT |
je .not_urgent |
; Ignore bogus urgent offsets |
movzx eax, [edx + TCP_header.UrgentPointer] |
add eax, [ebx + STREAM_SOCKET.rcv.size] |
cmp eax, SOCKET_MAXDATA |
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 in the segment (1094) |
.do_data: |
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT |
jae .final_processing |
test [edx + TCP_header.Flags], TH_FIN |
jnz @f |
test ecx, ecx |
jnz .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 |
movzx esi, [edx + TCP_header.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: |
; Uh-oh, some data is out of order, lets call TCP reassemble for help |
call TCP_reassemble |
DEBUGF 1, "1470\n" |
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW |
.data_done: |
;--------------- |
; FIN processing |
test [edx + TCP_header.Flags], TH_FIN |
jz .final_processing |
DEBUGF 1,"TCP_input: Processing FIN\n" |
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT |
jae .not_first_fin |
DEBUGF 1,"TCP_input: First FIN for this connection\n" |
mov eax, ebx |
call SOCKET_cant_recv_more |
mov [ebx + TCP_SOCKET.t_flags], TF_ACKNOW |
inc [ebx + TCP_SOCKET.RCV_NXT] |
.not_first_fin: |
mov eax, [ebx + TCP_SOCKET.t_state] |
shl eax, 2 |
jmp dword [eax + .FIN_sw_list] |
.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: |
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT |
jmp .final_processing |
.fin_wait1: |
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING |
jmp .final_processing |
.fin_wait2: |
mov [ebx + TCP_SOCKET.t_state], TCPS_TIMED_WAIT |
mov eax, ebx |
call TCP_cancel_timers |
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL |
call SOCKET_is_disconnected |
jmp .final_processing |
.fin_timed: |
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL |
jmp .final_processing |
.drop_after_ack: |
DEBUGF 1,"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 .dumpit |
or [eax + TCP_SOCKET.t_flags], TF_ACKNOW |
jmp .need_output |
.drop_with_reset: |
DEBUGF 1,"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 .dumpit |
;;; 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 .dumpit |
;----------------- |
; Final processing |
.final_processing: |
DEBUGF 1,"TCP_input: Final processing\n" |
push ebx |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
pop eax |
test [eax + TCP_SOCKET.temp_bits], TCP_BIT_NEEDOUTPUT |
jnz .need_output |
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW |
jz .dumpit |
DEBUGF 1,"TCP_input: ACK now!\n" |
.need_output: |
DEBUGF 1,"TCP_input: need output\n" |
call TCP_output |
.dumpit: |
DEBUGF 1,"TCP_input: dumping\n" |
call kernel_free |
add esp, 4 |
jmp .loop |
;--------- |
; Respond |
.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 |
.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 |
call TCP_respond_segment |
jmp .drop_no_socket |
.respond_seg_syn: |
mov cl, TH_RST + TH_ACK |
call TCP_respond_segment |
jmp .drop_no_socket |
;----- |
; Drop |
.drop: |
DEBUGF 1,"TCP_input: Dropping segment\n" |
pusha |
lea ecx, [ebx + SOCKET.mutex] |
call mutex_unlock |
popa |
.destroy_new_socket: |
test [ebx + TCP_SOCKET.temp_bits], TCP_BIT_DROPSOCKET |
jz .drop_no_socket |
mov eax, ebx |
call SOCKET_free |
.drop_no_socket: |
DEBUGF 1,"TCP_input: Drop (no socket)\n" |
call kernel_free |
add esp, 4 |
jmp .loop |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/tcp.inc |
---|
0,0 → 1,224 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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_TIMED_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 |
; 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 |
; 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 |
; bits used by tcp_input and tcp_output |
TCP_BIT_NEEDOUTPUT = 1 shl 0 |
TCP_BIT_TIMESTAMP = 1 shl 1 |
TCP_BIT_DROPSOCKET = 1 shl 2 |
TCP_BIT_SENDALOT = 1 shl 0 |
TCP_PAWS_IDLE = 24*24*60*60*100 ; 24 days, in 1/100 seconds |
TCP_QUEUE_SIZE = 50 |
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 ? |
buffer_ptr dd ? |
timestamp dd ? |
ends |
align 4 |
uglobal |
TCP_segments_tx rd MAX_NET_DEVICES |
TCP_segments_rx rd MAX_NET_DEVICES |
TCP_segments_missed rd MAX_NET_DEVICES |
TCP_segments_dumped rd MAX_NET_DEVICES |
; TCP_bytes_rx rq MAX_NET_DEVICES |
; TCP_bytes_tx rq MAX_NET_DEVICES |
TCP_sequence_num dd ? |
TCP_queue rd TCP_QUEUE_SIZE*sizeof.TCP_queue_entry/4 |
TCP_input_event dd ? |
endg |
;----------------------------------------------------------------- |
; |
; TCP_init |
; |
; This function resets all TCP variables |
; |
;----------------------------------------------------------------- |
macro TCP_init { |
xor eax, eax |
mov edi, TCP_segments_tx |
mov ecx, (6*MAX_NET_DEVICES) |
rep stosd |
pseudo_random eax |
mov [TCP_sequence_num], eax |
init_queue TCP_queue |
push 1 |
pop ebx |
mov ecx, TCP_process_input |
call new_sys_threads |
} |
include 'tcp_timer.inc' |
include 'tcp_subr.inc' |
include 'tcp_usreq.inc' |
include 'tcp_input.inc' |
include 'tcp_output.inc' |
;--------------------------------------------------------------------------- |
; |
; TCP_API |
; |
; This function is called by system function 76 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
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 |
.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 |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/ARP.inc |
---|
0,0 → 1,645 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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 |
align 4 |
uglobal |
NumARP dd ? |
ARP_table rb ARP_TABLE_SIZE * sizeof.ARP_entry ; TODO: separate ARP table and stats per interface |
ARP_PACKETS_TX rd MAX_NET_DEVICES |
ARP_PACKETS_RX rd MAX_NET_DEVICES |
ARP_CONFLICTS rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; ARP_init |
; |
; This function resets all ARP variables |
; |
;----------------------------------------------------------------- |
macro ARP_init { |
xor eax, eax |
mov [NumARP], eax |
mov edi, ARP_PACKETS_TX |
mov ecx, 3*MAX_NET_DEVICES |
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 |
mov ecx, [NumARP] |
test ecx, ecx |
jz .exit |
mov 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 ecx |
call ARP_del_entry |
pop ecx esi |
jmp .next |
.response_timeout: |
mov [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT |
mov [esi + ARP_entry.TTL], 10 |
jmp .next |
.exit: |
} |
;----------------------------------------------------------------- |
; |
; ARP_input |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; packet size (without ethernet header) in ecx |
; packet ptr in edx |
; device ptr in ebx |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
ARP_input: |
;----------------------------------------- |
; Check validity and print some debug info |
cmp ecx, sizeof.ARP_header |
jb .exit |
call NET_ptr_to_num |
cmp edi, -1 |
jz .exit |
inc [ARP_PACKETS_RX + 4*edi] ; update stats |
DEBUGF 1,"ARP_input: got packet from %u.%u.%u.%u through device %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, [IP_LIST + 4*edi] |
je .collision |
;--------------------- |
; Handle reply packets |
cmp [edx + ARP_header.Opcode], ARP_REP_OPCODE |
jne .maybe_request |
DEBUGF 1,"ARP_input: It's a reply\n" |
mov ecx, [NumARP] |
test ecx, ecx |
jz .exit |
mov esi, ARP_table |
.loop: |
cmp [esi + ARP_entry.IP], eax |
je .gotit |
add esi, sizeof.ARP_entry |
dec ecx |
jnz .loop |
DEBUGF 1,"ARP_input: no matching entry found\n" |
jmp .exit |
.gotit: |
DEBUGF 1,"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 1,"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 1,"ARP_input: its a request\n" |
mov eax, [IP_LIST + 4*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_DRV_LIST + 4*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] |
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 1,"ARP_input: Sending reply\n" |
call [ebx + NET_DEVICE.transmit] |
ret |
.collision: |
inc [ARP_CONFLICTS + 4*edi] |
DEBUGF 1,"ARP_input: IP address conflict detected!\n" |
.exit: |
call kernel_free |
add esp, 4 ; pop (balance stack) |
DEBUGF 1,"ARP_input: exiting\n" |
ret |
;--------------------------------------------------------------------------- |
; |
; ARP_output_request |
; |
; IN: ip in eax |
; device in edi |
; OUT: / |
; |
;--------------------------------------------------------------------------- |
align 4 |
ARP_output_request: |
push eax ; DestIP |
pushd [IP_LIST + edi] ; SenderIP |
inc [ARP_PACKETS_TX + edi] ; assume we will succeed |
DEBUGF 1,"ARP_output_request: ip=%u.%u.%u.%u\n",\ |
[esp + 4]:1, [esp + 5]:1, [esp + 6]:1, [esp + 7]:1 |
mov ebx, [NET_DRV_LIST + edi] ; device ptr |
lea eax, [ebx + ETH_DEVICE.mac] ; local device mac |
mov edx, ETH_BROADCAST ; broadcast mac |
mov ecx, sizeof.ARP_header |
mov di, ETHER_ARP |
call ETH_output |
jz .exit |
mov ecx, eax |
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 ; |
pop eax ; SenderIP |
stosd ; |
mov eax, -1 ; DestMac |
stosd ; |
stosw ; |
pop eax ; DestIP |
stosd ; |
DEBUGF 1,"ARP_output_request: device=%x\n", ebx |
push edx ecx |
call [ebx + NET_DEVICE.transmit] |
ret |
.exit: |
add esp, 4 + 4 |
DEBUGF 1,"ARP_output_request: failed\n" |
sub eax, eax |
ret |
;----------------------------------------------------------------- |
; |
; ARP_add_entry (or update) |
; |
; IN: esi = ptr to entry (can easily be made on the stack) |
; OUT: eax = entry #, -1 on error |
; edi = ptr to newly created entry |
; |
;----------------------------------------------------------------- ; TODO: use a mutex |
align 4 |
ARP_add_entry: |
DEBUGF 1,"ARP_add_entry: " |
mov ecx, [NumARP] |
cmp ecx, ARP_TABLE_SIZE ; list full ? |
jae .error |
xor eax, eax |
mov edi, ARP_table |
mov ecx, [esi + ARP_entry.IP] |
.loop: |
cmp [edi + ARP_entry.Status], ARP_NO_ENTRY ; is this slot empty? |
je .add |
cmp [edi + ARP_entry.IP], ecx ; 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 |
.maybe_next: ; try the next slot |
add edi, sizeof.ARP_entry |
inc eax |
cmp eax, ARP_TABLE_SIZE |
jae .error |
jmp .loop |
.add: |
mov ecx, sizeof.ARP_entry/2 |
rep movsw |
inc [NumARP] |
sub edi, sizeof.ARP_entry |
DEBUGF 1,"entry=%u\n", eax |
ret |
.error: |
DEBUGF 1,"failed\n" |
mov eax, -1 |
ret |
;----------------------------------------------------------------- |
; |
; ARP_del_entry |
; |
; IN: esi = ptr to arp entry |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
ARP_del_entry: |
DEBUGF 1,"ARP_del_entry: entry=%x entrys=%u\n", esi, [NumARP] |
DEBUGF 1,"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 |
mov ecx, ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry |
sub ecx, esi |
shr ecx, 1 |
mov edi, esi |
add esi, sizeof.ARP_entry |
rep movsw |
xor eax, eax |
mov ecx, sizeof.ARP_entry/2 |
rep stosw |
dec [NumARP] |
DEBUGF 1,"ARP_del_entry: success\n" |
ret |
;----------------------------------------------------------------- |
; |
; ARP_IP_to_MAC |
; |
; This function translates an IP address to a MAC address |
; |
; IN: eax = IPv4 address |
; edi = device number |
; OUT: eax = -1 on error, -2 means request send |
; else, ax = first two bytes of mac (high 16 bits of eax will be 0) |
; ebx = last four bytes of mac |
; edi = unchanged |
; |
;----------------------------------------------------------------- |
align 4 |
ARP_IP_to_MAC: |
DEBUGF 1,"ARP_IP_to_MAC: %u.%u", al, ah |
rol eax, 16 |
DEBUGF 1,".%u.%u\n", al, ah |
rol eax, 16 |
cmp eax, 0xffffffff |
je .broadcast |
;-------------------------------- |
; Try to find the IP in ARP_table |
mov ecx, [NumARP] |
test ecx, ecx |
jz .not_in_list |
mov esi, ARP_table + ARP_entry.IP |
.scan_loop: |
cmp [esi], eax |
je .found_it |
add esi, sizeof.ARP_entry |
loop .scan_loop |
.not_in_list: |
DEBUGF 1,"ARP_IP_to_MAC: preparing for ARP request\n" |
;-------------------- |
; Send an ARP request |
push eax edi ; save IP for ARP_output_request |
; Now create the ARP entry |
pushw ARP_REQUEST_TTL ; TTL |
pushw ARP_AWAITING_RESPONSE ; status |
pushd 0 ; mac |
pushw 0 |
pushd eax ; ip |
mov esi, esp |
call ARP_add_entry |
add esp, sizeof.ARP_entry ; clear the entry from stack |
cmp eax, -1 ; did ARP_add_entry fail? |
je .full |
mov esi, edi |
pop edi eax ; IP in eax, device number in edi, for ARP_output_request |
push esi edi |
call ARP_output_request ; And send a request |
pop edi esi |
;----------------------------------------------- |
; At this point, we got an ARP entry in the list |
.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 1,"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 1,"ARP_IP_to_MAC: table is full!\n" |
add esp, 8 |
.give_up: |
DEBUGF 1,"ARP_IP_to_MAC: entry has no valid mapping!\n" |
mov eax, -1 |
ret |
.broadcast: |
mov eax, 0x0000ffff |
mov ebx, 0xffffffff |
ret |
;----------------------------------------------------------------- |
; |
; ARP_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: ? |
; |
;----------------------------------------------------------------- |
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, [NumARP] |
ret |
.read: |
cmp ecx, [NumARP] |
jae .error |
; edi = pointer to buffer |
; ecx = # entry |
imul ecx, sizeof.ARP_entry |
add ecx, ARP_table |
mov esi, ecx |
mov ecx, sizeof.ARP_entry/2 |
rep movsw |
xor eax, eax |
ret |
.write: |
; esi = pointer to buffer |
call ARP_add_entry ; out: eax = entry number, -1 on error |
ret |
.remove: |
; ecx = # entry |
cmp ecx, [NumARP] |
jae .error |
imul ecx, sizeof.ARP_entry |
lea esi, [ARP_table + ecx] |
call ARP_del_entry |
ret |
.send_announce: |
mov edi, eax |
mov eax, [IP_LIST + eax] |
call ARP_output_request ; now send a gratuitous ARP |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/ethernet.inc |
---|
0,0 → 1,233 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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 |
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 |
align 4 |
iglobal |
ETH_BROADCAST dp 0xffffffffffff |
endg |
;----------------------------------------------------------------- |
; |
; ETH_input |
; |
; This function is called by ethernet drivers, |
; It pushes the received ethernet packets onto the eth_in_queue |
; |
; IN: [esp] = Pointer to buffer |
; [esp+4] = size of buffer |
; ebx = pointer to eth_device |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
ETH_input: |
mov eax, [esp] |
mov ecx, [esp+4] |
DEBUGF 1,"ETH_input: size=%u\n", ecx |
cmp ecx, ETH_FRAME_MINIMUM |
jb .dump |
sub ecx, sizeof.ETH_header |
lea edx, [eax + sizeof.ETH_header] |
mov ax, [eax + ETH_header.Type] |
cmp ax, ETHER_IPv4 |
je IPv4_input |
cmp ax, ETHER_ARP |
je ARP_input |
cmp ax, ETHER_IPv6 |
je IPv6_input |
cmp ax, ETHER_PPP_DISCOVERY |
je PPPoE_discovery_input |
cmp ax, ETHER_PPP_SESSION |
je PPPoE_session_input |
DEBUGF 2,"ETH_input: Unknown packet type=%x\n", ax |
.dump: |
DEBUGF 2,"ETH_input: dumping\n" |
call kernel_free |
add esp, 4 |
ret |
;----------------------------------------------------------------- |
; |
; ETH_output |
; |
; IN: eax = pointer to source mac |
; ebx = device ptr |
; ecx = packet size |
; edx = pointer to destination mac |
; di = protocol |
; |
; OUT: edi = 0 on error, pointer to buffer otherwise |
; eax = buffer start |
; ebx = to device structure |
; ecx = unchanged (packet size of embedded data) |
; edx = size of complete buffer |
; |
;----------------------------------------------------------------- |
align 4 |
ETH_output: |
DEBUGF 1,"ETH_output: size=%u device=%x\n", ecx, ebx |
cmp ecx, [ebx + NET_DEVICE.mtu] |
ja .exit |
push ecx |
push di eax edx |
add ecx, sizeof.ETH_header |
stdcall kernel_alloc, ecx |
test eax, eax |
jz .out_of_ram |
mov edi, eax |
pop esi |
movsd |
movsw |
pop esi |
movsd |
movsw |
pop ax |
stosw |
lea eax, [edi - sizeof.ETH_header] ; 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: |
DEBUGF 1,"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: |
DEBUGF 2,"ETH_output: Out of ram!\n" |
add esp, 4+4+2+4 |
sub edi, edi |
ret |
.exit: |
DEBUGF 2,"ETH_output: Packet too large!\n" |
sub edi, edi |
ret |
;----------------------------------------------------------------- |
; |
; ETH_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;----------------------------------------------------------------- |
align 4 |
ETH_api: |
cmp bh, MAX_NET_DEVICES |
ja .error |
movzx eax, bh |
mov eax, dword [NET_DRV_LIST + 4*eax] |
cmp [eax + NET_DEVICE.type], NET_TYPE_ETH |
jne .error |
and ebx, 0xff |
cmp ebx, .number |
ja .error |
jmp dword [.table + 4*ebx] |
.table: |
dd .packets_tx ; 0 |
dd .packets_rx ; 1 |
dd .bytes_tx ; 2 |
dd .bytes_rx ; 3 |
dd .read_mac ; 4 |
dd .state ; 5 |
.number = ($ - .table) / 4 - 1 |
.error: |
or eax, -1 |
ret |
.packets_tx: |
mov eax, [eax + NET_DEVICE.packets_tx] |
ret |
.packets_rx: |
mov eax, [eax + NET_DEVICE.packets_rx] |
ret |
.bytes_tx: |
mov ebx, dword [eax + NET_DEVICE.bytes_tx + 4] |
mov eax, dword [eax + NET_DEVICE.bytes_tx] |
mov [esp+20+4], ebx ; TODO: fix this ugly code |
ret |
.bytes_rx: |
mov ebx, dword [eax + NET_DEVICE.bytes_rx + 4] |
mov eax, dword [eax + NET_DEVICE.bytes_rx] |
mov [esp+20+4], ebx ; TODO: fix this ugly code |
ret |
.read_mac: |
movzx ebx, word [eax + ETH_DEVICE.mac] |
mov eax, dword [eax + ETH_DEVICE.mac + 2] |
mov [esp+20+4], ebx ; TODO: fix this ugly code |
ret |
.state: |
mov eax, [eax + NET_DEVICE.state] |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/tcp_output.inc |
---|
0,0 → 1,621 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. 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_output |
; |
; IN: eax = socket pointer |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
TCP_output: |
DEBUGF 1,"TCP_output: socket=%x\n", eax |
push eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
pop eax |
; 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 [eax + TCP_SOCKET.temp_bits], 0 |
mov ebx, [eax + TCP_SOCKET.SND_NXT] ; calculate offset (71) |
sub ebx, [eax + TCP_SOCKET.SND_UNA] ; |
mov ecx, [eax + TCP_SOCKET.SND_WND] ; determine window |
cmp ecx, [eax + TCP_SOCKET.SND_CWND] ; |
jb @f ; |
mov ecx, [eax + TCP_SOCKET.SND_CWND] ; |
@@: ; |
call TCP_outflags ; flags in dl |
;------------------------ |
; 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 |
cmp [eax + TCP_SOCKET.t_force], 0 |
je .no_force |
DEBUGF 1,"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: |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_rxtshift], 0 |
.no_force: |
;-------------------------------- |
; Calculate how much data to send (106) |
mov esi, [eax + STREAM_SOCKET.snd.size] |
cmp esi, ecx |
jb @f |
mov esi, ecx |
@@: |
sub esi, ebx |
;------------------------ |
; check for window shrink (107) |
; If FIN has been set, but not ACKed, but we havent been called to retransmit, esi will be -1 |
; Otherwise, window shrank after we sent into it. |
jae .not_persist |
; enter persist state |
xor esi, esi |
; If window shrank to 0 |
test ecx, ecx |
jnz @f |
; cancel pending retransmit |
mov [eax + TCP_SOCKET.timer_retransmission], 0 |
; 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 (124) |
cmp esi, [eax + TCP_SOCKET.t_maxseg] |
jbe @f |
mov esi, [eax + TCP_SOCKET.t_maxseg] |
or [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT |
@@: |
;-------------------------------------------- |
; Turn of FIN flag if send buffer not emptied (128) |
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 (130) |
mov ecx, SOCKET_MAXDATA |
sub ecx, [eax + STREAM_SOCKET.rcv.size] |
;------------------------------ |
; Sender silly window avoidance (131) |
test esi, esi |
jz .len_zero |
cmp esi, [eax + TCP_SOCKET.t_maxseg] |
je TCP_send |
add ebx, esi ; offset + length |
cmp ebx, [eax + STREAM_SOCKET.snd.size] |
jb @f |
test [eax + TCP_SOCKET.t_flags], TF_NODELAY |
jnz TCP_send |
mov ebx, [eax + TCP_SOCKET.SND_MAX] |
cmp ebx, [eax + TCP_SOCKET.SND_UNA] |
je TCP_send |
@@: |
test [eax + TCP_SOCKET.t_force], -1 ;;; |
jnz TCP_send |
mov ebx, [eax + TCP_SOCKET.max_sndwnd] |
shr ebx, 1 |
cmp esi, ebx |
jae TCP_send |
mov ebx, [eax + TCP_SOCKET.SND_NXT] |
cmp ebx, [eax + TCP_SOCKET.SND_MAX] |
jb TCP_send |
.len_zero: |
;---------------------------------------- |
; Check if a window update should be sent (154) |
DEBUGF 1,"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 |
cmp ebx, ecx |
jb @f |
mov ebx, ecx |
@@: |
sub ebx, [eax + TCP_SOCKET.RCV_ADV] |
add ebx, [eax + TCP_SOCKET.RCV_NXT] |
mov edi, [eax + TCP_SOCKET.t_maxseg] |
shl edi, 1 |
; cmp ebx, edi |
; jae TCP_send |
; cmp ebx, [eax + TCP_SOCKET.] ;;; TODO: check with receive buffer high water mark |
; jae TCP_send |
.no_window: |
;-------------------------- |
; Should a segment be sent? (174) |
DEBUGF 1,"TCP_output: 174\n" |
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW ; we need to ACK |
jnz TCP_send |
test dl, TH_SYN + TH_RST ; we need to send a SYN or RST |
jnz TCP_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 TCP_send |
test dl, TH_FIN |
jz .enter_persist ; no reason to send, enter persist state |
; FIN was set, only send if not already sent, or on retransmit |
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN |
jz TCP_send |
mov ebx, [eax + TCP_SOCKET.SND_NXT] |
cmp ebx, [eax + TCP_SOCKET.SND_UNA] |
je TCP_send |
;-------------------- |
; Enter persist state (191) |
.enter_persist: |
cmp [eax + STREAM_SOCKET.snd.size], 0 ; Data ready to send? |
jne @f |
cmp [eax + TCP_SOCKET.timer_retransmission], 0 |
jne @f |
cmp [eax + TCP_SOCKET.timer_persist], 0 ; Persist timer already expired? |
jne @f |
DEBUGF 1,"TCP_output: Entering persist state\n" |
mov [eax + TCP_SOCKET.t_rxtshift], 0 |
call TCP_set_persist |
@@: |
;---------------------------- |
; No reason to send a segment (219) |
DEBUGF 1,"TCP_output: No reason to send a segment\n" |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
popa |
; Fixme: returnvalue? |
ret |
;----------------------------------------------- |
; |
; Send a segment (222) |
; |
; eax = socket pointer |
; esi = data len |
; dl = flags |
; |
;----------------------------------------------- |
align 4 |
TCP_send: |
DEBUGF 1,"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 1,"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 1,"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 1,"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 (270) |
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 [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT |
.no_overflow: |
;----------------------------------------------------------------- |
; Start by pushing all TCP header values in reverse order on stack |
; (essentially, creating the tcp header on the stack!) |
pushw 0 ; .UrgentPointer dw ? |
pushw 0 ; .Checksum dw ? |
pushw 0x00a0 ; .Window dw ? ;;;;;;; FIXME (370) |
shl edi, 2 ; .DataOffset db ? only 4 left-most bits |
shl dx, 8 |
or dx, di ; .Flags db ? |
pushw dx |
shr edi, 2 ; .DataOffset db ? |
push [eax + TCP_SOCKET.RCV_NXT] ; .AckNumber dd ? |
ntohd [esp] |
push [eax + TCP_SOCKET.SND_NXT] ; .SequenceNumber dd ? |
ntohd [esp] |
push [eax + TCP_SOCKET.RemotePort] ; .DestinationPort dw ? |
push [eax + TCP_SOCKET.LocalPort] ; .SourcePort dw ? |
push edi ; header size |
;--------------------- |
; Create the IP packet |
mov ecx, esi |
mov ebx, [eax + SOCKET.device] |
mov edx, [eax + IP_SOCKET.LocalIP] ; source ip |
mov eax, [eax + IP_SOCKET.RemoteIP] ; dest ip |
mov di, IP_PROTO_TCP shl 8 + 128 |
call IPv4_output |
jz .ip_error |
;----------------------------------------- |
; Move TCP header from stack to TCP packet |
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 edx ; packet size for send proc |
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 + 16] ; 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 <<< CHECKME |
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 + 12] ; socket ptr |
;---------------------------------- |
; initialize retransmit timer (400) |
;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 |
;TODO: update stats |
@@: |
; set retransmission timer if not already set, and not doing an ACK or keepalive probe |
cmp [eax + TCP_SOCKET.timer_retransmission], 0 ;;;; FIXME |
ja .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 |
cmp [eax + TCP_SOCKET.timer_persist], 0 |
jne .retransmit_set |
mov [eax + TCP_SOCKET.timer_persist], 0 |
mov [eax + TCP_SOCKET.t_rxtshift], 0 |
.retransmit_set: |
;-------------------- |
; Create the checksum |
TCP_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP) |
mov [esi + TCP_header.Checksum], dx |
;---------------- |
; Send the packet |
DEBUGF 1,"TCP_send: Sending with device %x\n", ebx |
call [ebx + NET_DEVICE.transmit] |
jnz .send_error |
;--------------- |
; Ok, data sent! |
pop ecx |
pop eax |
inc [TCP_segments_tx] ; FIXME: correct interface? |
; update advertised receive 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] |
; and flags |
and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK) |
;-------------- |
; unlock socket |
push eax |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
pop eax |
;----------------------------- |
; Check if we need more output |
test [eax + TCP_SOCKET.temp_bits], TCP_BIT_SENDALOT |
jnz TCP_output.again |
DEBUGF 1,"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 |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
DEBUGF 1,"TCP_send: IP error\n" |
or eax, -1 |
ret |
.send_error: |
add esp, 8 |
lea ecx, [eax + SOCKET.mutex] |
call mutex_unlock |
DEBUGF 1,"TCP_send: sending failed\n" |
or eax, -2 |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/tcp_usreq.inc |
---|
0,0 → 1,102 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;------------------------- |
; |
; TCP_usrclose |
; |
; Move connection to next state, based on process close. |
; |
; IN: eax = socket ptr |
; |
;------------------------- |
align 4 |
TCP_usrclosed: |
DEBUGF 1,"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 |
; TODO: set timer? |
pop ebx |
ret |
.last_ack: |
mov [eax + TCP_SOCKET.t_state], TCPS_LAST_ACK |
pop ebx |
ret |
.disc: |
call SOCKET_is_disconnected |
; TODO: set timer? |
.ret: |
pop ebx |
ret |
;------------------------- |
; |
; TCP_disconnect |
; |
; IN: eax = socket ptr |
; OUT: eax = socket ptr |
; |
;------------------------- |
align 4 |
TCP_disconnect: |
DEBUGF 1,"TCP_disconnect: %x\n", eax |
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED |
jb TCP_close |
; TODO: implement LINGER ? |
call SOCKET_is_disconnecting |
call TCP_usrclosed |
call TCP_output |
ret |
/kernel/branches/net/network/IPv6.inc |
---|
0,0 → 1,298 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2012-2013. 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 |
align 4 |
uglobal |
IPv6: |
.addresses rd 4*MAX_NET_DEVICES |
.subnet rd 4*MAX_NET_DEVICES |
.dns rd 4*MAX_NET_DEVICES |
.gateway rd 4*MAX_NET_DEVICES |
.packets_tx rd MAX_NET_DEVICES |
.packets_rx rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; IPv6_init |
; |
; This function resets all IP variables |
; |
;----------------------------------------------------------------- |
macro IPv6_init { |
xor eax, eax |
mov edi, IPv6 |
mov ecx, (4*4*4+2*4)MAX_IP |
rep stosd |
} |
;----------------------------------------------------------------- |
; |
; IPv6_input: |
; |
; Will check if IPv6 Packet isnt damaged |
; and call appropriate handler. (TCP/UDP/ICMP/..) |
; |
; It will also re-construct fragmented packets |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; pointer to IPv6 header in edx |
; size of IPv6 packet in ecx |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
IPv6_input: |
DEBUGF 2,"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 1,"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 2,"IPv6_input - unknown protocol: %u\n", al |
.dump: |
DEBUGF 1,"IPv6_input - dumping\n" |
call kernel_free |
add esp, 4 |
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 1,"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 1,"IPv6_input - pad %u\n", eax |
inc esi |
inc esi |
add esi, eax |
sub ecx, eax |
jmp .hop_by_hop |
.pad_1: |
DEBUGF 1,"IPv6_input - pad 1\n" |
inc esi |
dec ecx |
jmp .hop_by_hop |
.dest_opts: |
DEBUGF 1,"IPv6_input - dest opts\n" |
jmp .nextheader |
.routing: |
DEBUGF 1,"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 1,"IPv6_input - fragment\n" |
jmp .nextheader |
;--------------------------------------------------------------------------- |
; |
; IPv6_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/loopback.inc |
---|
0,0 → 1,126 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. 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: 2891 $ |
iglobal |
LOOPBACK_DEVICE: |
.type dd NET_TYPE_LOOPBACK |
.mtu dd 4096 |
.name dd .namestr |
.unload dd .dummy_fn |
.reset dd .dummy_fn |
.transmit dd LOOP_input |
.bytes_tx dq 0 |
.bytes_rx dq 0 |
.packets_tx dd 0 |
.packets_rx dd 0 |
.namestr db 'loopback', 0 |
.dummy_fn: |
ret |
endg |
;----------------------------------------------------------------- |
; |
; LOOP_input |
; |
; IN: [esp+4] = Pointer to buffer |
; [esp+8] = size of buffer |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
LOOP_input: |
pop ebx |
pop eax |
pop ecx |
push ebx |
push ecx |
push eax |
DEBUGF 1,"LOOP_input: size=%u\n", ecx |
lea edx, [eax + 2] |
mov ax, word[eax] |
mov ebx, LOOPBACK_DEVICE |
cmp ax, ETHER_IPv4 |
je IPv4_input |
DEBUGF 2,"LOOP_input: Unknown packet type=%x\n", ax |
.dump: |
DEBUGF 2,"LOOP_input: dumping\n" |
call kernel_free |
add esp, 4 |
ret |
;----------------------------------------------------------------- |
; |
; LOOP_output |
; |
; IN: |
; ecx = packet size |
; di = protocol |
; |
; OUT: edi = 0 on error, pointer to buffer otherwise |
; eax = buffer start |
; ebx = to device structure |
; ecx = unchanged (packet size of embedded data) |
; edx = size of complete buffer |
; |
;----------------------------------------------------------------- |
align 4 |
LOOP_output: |
DEBUGF 1,"LOOP_output\n" |
push ecx |
push di |
add ecx, 2 |
cmp ecx, [LOOPBACK_DEVICE.mtu] |
ja .out_of_ram |
stdcall kernel_alloc, ecx |
test eax, eax |
jz .out_of_ram |
mov edi, eax |
pop ax |
stosw |
lea eax, [edi - 2] ; Set eax to buffer start |
pop ecx |
lea edx, [ecx + 2] ; Set edx to complete buffer size |
mov ebx, LOOPBACK_DEVICE |
.done: |
DEBUGF 2,"LOOP_output: ptr=%x size=%u\n", eax, edx |
ret |
.out_of_ram: |
DEBUGF 2,"LOOP_output: failed\n" |
add esp, 2+4 |
sub edi, edi |
ret |
/kernel/branches/net/network/tcp_timer.inc |
---|
0,0 → 1,168 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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$ |
;---------------------- |
; 160 ms timer |
;---------------------- |
macro TCP_timer_160ms { |
local .loop |
local .exit |
mov ebx, net_sockets |
.loop: |
mov ebx, [ebx + SOCKET.NextPtr] |
or 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) |
push ebx |
mov cl, TH_ACK |
call TCP_respond |
; and [ebx + TCP_SOCKET.t_flags], TF_ACKNOW ;; |
; mov eax, ebx ;; |
; call TCP_output ;; |
pop ebx |
jmp .loop |
.exit: |
} |
;---------------------- |
; 640 ms timer |
;---------------------- |
macro TCP_timer_640ms { |
local .loop |
local .exit |
; Update TCP sequence number |
add [TCP_sequence_num], 64000 |
; scan through all the active TCP sockets, decrementing ALL timers |
; timers do not have the chance to wrap because the keepalive timer will kill the socket when it expires |
mov eax, net_sockets |
.loop: |
mov eax, [eax + SOCKET.NextPtr] |
.check_only: |
or eax, eax |
jz .exit |
cmp [eax + SOCKET.Domain], AF_INET4 |
jne .loop |
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP |
jne .loop |
inc [eax + TCP_SOCKET.t_idle] |
dec [eax + TCP_SOCKET.timer_retransmission] |
jnz .check_more2 |
DEBUGF 1,"socket %x: Retransmission timer expired\n", eax |
push eax |
call TCP_output |
pop eax |
.check_more2: |
dec [eax + TCP_SOCKET.timer_keepalive] |
jnz .check_more3 |
DEBUGF 1,"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: |
dec [eax + TCP_SOCKET.timer_timed_wait] |
jnz .check_more5 |
DEBUGF 1,"socket %x: 2MSL timer expired\n", eax |
.check_more5: |
dec [eax + TCP_SOCKET.timer_persist] |
jnz .loop |
DEBUGF 1,"socket %x: persist timer expired\n", eax |
call TCP_set_persist |
mov [eax + TCP_SOCKET.t_force], 1 |
push eax |
call TCP_output |
pop eax |
mov [eax + TCP_SOCKET.t_force], 0 |
jmp .loop |
.exit: |
} |
; eax = socket |
TCP_cancel_timers: |
push eax edi |
lea edi, [eax + TCP_SOCKET.timer_retransmission] |
xor eax, eax |
stosd |
stosd |
stosd |
stosd |
stosd |
pop edi eax |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/udp.inc |
---|
0,0 → 1,325 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
align 4 |
uglobal |
UDP_PACKETS_TX rd MAX_NET_DEVICES |
UDP_PACKETS_RX rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; UDP_init |
; |
; This function resets all UDP variables |
; |
;----------------------------------------------------------------- |
macro UDP_init { |
xor eax, eax |
mov edi, UDP_PACKETS_TX |
mov ecx, 2*MAX_NET_DEVICES |
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, [IP1+1] |
adc dh, [IP1+0] |
adc dl, [IP1+3] |
adc dh, [IP1+2] |
adc dl, [IP2+1] |
adc dh, [IP2+0] |
adc dl, [IP2+3] |
adc dh, [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: |
; |
; Called by IPv4_input, |
; this procedure will inject the udp data diagrams in the application sockets. |
; |
; IN: [esp] = Pointer to buffer |
; [esp+4] = size of buffer |
; ebx = ptr to device struct |
; ecx = UDP Packet size |
; esi = ptr to UDP header |
; edi = ptr to ipv4 source and dest address |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
UDP_input: |
DEBUGF 1,"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 |
UDP_checksum (edi), (edi+4) |
jnz .checksum_mismatch |
.no_checksum: |
DEBUGF 1,"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 |
mov cx, [esi + UDP_header.SourcePort] |
mov dx, [esi + UDP_header.DestinationPort] |
mov edi, [edi + 4] ; ipv4 source address |
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_UDP |
jne .next_socket |
cmp [eax + UDP_SOCKET.LocalPort], dx |
jne .next_socket |
DEBUGF 1,"UDP_input: socket=%x\n", eax |
;;; TODO: when packet is processed, check more sockets! |
; cmp [eax + IP_SOCKET.RemoteIP], 0xffffffff |
; je @f |
; cmp [eax + IP_SOCKET.RemoteIP], edi |
; jne .next_socket |
; @@: |
; |
; FIXME: UDP should check remote IP, but not under all circumstances! |
cmp [eax + UDP_SOCKET.firstpacket], 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] ; Fixme: correct interface? |
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 1,"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 |
inc [eax + UDP_SOCKET.firstpacket] |
jmp .updatesock |
.checksum_mismatch: |
DEBUGF 2,"UDP_input: checksum mismatch\n" |
.dump: |
call kernel_free |
add esp, 4 ; pop (balance stack) |
DEBUGF 2,"UDP_input: dumping\n" |
ret |
;----------------------------------------------------------------- |
; |
; UDP_output |
; |
; IN: eax = socket pointer |
; ecx = number of bytes to send |
; esi = pointer to data |
; |
;----------------------------------------------------------------- |
align 4 |
UDP_output: |
DEBUGF 1,"UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi |
mov dx, [eax + UDP_SOCKET.RemotePort] |
DEBUGF 1,"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 1,"local port=%x\n", dx |
sub esp, 8 ; Data ptr and data size will be placed here |
push edx esi |
mov ebx, [eax + SOCKET.device] |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
mov di, IP_PROTO_UDP shl 8 + 128 |
add ecx, sizeof.UDP_header |
call IPv4_output |
jz .fail |
mov [esp + 8], eax ; pointer to buffer start |
mov [esp + 8 + 4], edx ; buffer size |
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 1,"UDP_output: sending with device %x\n", ebx |
call [ebx + NET_DEVICE.transmit] |
test eax, eax |
jnz @f |
inc [UDP_PACKETS_TX] ; FIXME: correct device? |
@@: |
ret |
.fail: |
DEBUGF 1,"UDP_output: failed\n" |
add esp, 4+4+8 |
or eax, -1 |
ret |
;--------------------------------------------------------------------------- |
; |
; UDP_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;--------------------------------------------------------------------------- |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/PPPoE.inc |
---|
0,0 → 1,340 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2012. 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 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
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 |
PPPoE_SID dw ? |
PPPoE_MAC dp ? |
endg |
;----------------------------------------------------------------- |
; |
; PPPoE_init |
; |
; This function resets all IP variables |
; |
;----------------------------------------------------------------- |
macro PPPoE_init { |
call PPPoE_stop_connection |
} |
;----------------------------------------------------------------- |
; |
; PPPoE discovery input |
; |
; Handler of received Ethernet packet with type = Discovery |
; |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; pointer to PPP header in edx |
; size of PPP packet in ecx |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
PPPoE_discovery_input: |
DEBUGF 2,"PPPoE_discovery_input\n" |
; First, find open PPPoE socket |
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 |
; Now, send it to the this socket |
mov ecx, [esp + 4] |
mov esi, [esp] |
jmp SOCKET_input |
.dump: |
DEBUGF 1,'PPPoE_discovery_input: dumping\n' |
call kernel_free |
add esp, 4 |
ret |
;-------------------------------------- |
; |
; Send discovery packet |
; |
; IN: eax = socket pointer |
; ecx = number of bytes to send |
; esi = pointer to data |
; |
;-------------------------------------- |
align 4 |
PPPoE_discovery_output: |
DEBUGF 2,"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, MAX_NET_DEVICES |
ja .bad |
mov ebx, [NET_DRV_LIST + 4*ebx] |
test ebx, ebx |
jz .bad |
cmp [ebx + NET_DEVICE.type], NET_TYPE_ETH |
jne .bad |
DEBUGF 2,"PPPoE_discovery_output: device=%x\n", ebx |
; Create packet. |
push ecx esi |
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_PPP_SESSION ; Allow only PPP_discovery, or LCP |
je @f |
mov ax, ETHER_PPP_DISCOVERY |
stosw |
@@: |
; And send the packet |
call [ebx + NET_DEVICE.transmit] |
xor eax, eax |
ret |
.bad: |
or eax, -1 |
ret |
;----------------------------------------------------------------- |
; |
; PPPoE session input |
; |
; Handler of received Ethernet packet with type = Session |
; |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; pointer to device struct in ebx |
; pointer to PPP header in edx |
; size of PPP packet in ecx |
; 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 2,"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_IPv4 |
je IPv4_input |
; cmp ax, PPP_IPv6 |
; je IPv6_input |
jmp PPPoE_discovery_input ; Send LCP,CHAP,CBCP,... packets to the PPP dialer |
DEBUGF 2,"PPPoE_input: Unknown protocol=%x\n", ax |
.dump: |
DEBUGF 2,"PPPoE_input: dumping\n" |
call kernel_free |
add esp, 4 |
ret |
;----------------------------------------------------------------- |
; |
; PPPoE_output |
; |
; IN: |
; ebx = device ptr |
; ecx = packet size |
; |
; di = protocol |
; |
; OUT: edi = 0 on error, pointer to buffer otherwise |
; eax = buffer start |
; ebx = to device structure |
; ecx = unchanged (packet size of embedded data) |
; edx = size of complete buffer |
; |
;----------------------------------------------------------------- |
align 4 |
PPPoE_output: |
DEBUGF 1,"PPPoE_output: size=%u device=%x\n", ecx, ebx |
pushw di |
pushw [PPPoE_SID] |
lea eax, [ebx + ETH_DEVICE.mac] |
lea edx, [PPPoE_MAC] |
add ecx, PPPoE_frame.Payload + 2 |
mov di, ETHER_PPP_SESSION |
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 1,"PPPoE_output: success!\n" |
ret |
.eth_error: |
add esp, 4 |
xor edi, edi |
ret |
PPPoE_start_connection: |
DEBUGF 2,"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 2,"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 |
; |
; This function is called by system function 75 |
; |
; 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 |
/kernel/branches/net/network/icmp.inc |
---|
0,0 → 1,431 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. 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 |
align 4 |
uglobal |
ICMP_PACKETS_TX rd MAX_NET_DEVICES |
ICMP_PACKETS_RX rd MAX_NET_DEVICES |
endg |
;----------------------------------------------------------------- |
; |
; ICMP_init |
; |
;----------------------------------------------------------------- |
macro ICMP_init { |
xor eax, eax |
mov edi, ICMP_PACKETS_TX |
mov ecx, 2*MAX_NET_DEVICES |
rep stosd |
} |
;----------------------------------------------------------------- |
; |
; ICMP_input: |
; |
; This procedure will send reply's to ICMP echo's |
; and insert packets into sockets when needed |
; |
; IN: Pointer to buffer in [esp] |
; size of buffer in [esp+4] |
; ebx = pointer to device struct |
; ecx = ICMP Packet size |
; esi = ptr to ICMP Packet data |
; edi = ptr to ipv4 source and dest address |
; |
; OUT: / |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_input: |
DEBUGF 1,"ICMP_input:\n" |
; First, check the checksum (altough some implementations ignore it) |
push esi ecx |
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 ecx edx |
jne .checksum_mismatch |
cmp [edx + ICMP_header.Type], ICMP_ECHO ; Is this an echo request? |
jne .check_sockets |
; We well re-use the packet so we can create the response as fast as possible |
; Notice: this only works on pure ethernet |
DEBUGF 1,"got echo request\n" |
mov [edx + ICMP_header.Type], ICMP_ECHOREPLY ; Change Packet type to reply |
mov esi, [esp] ; Start of buffer |
cmp dword[edi + 4], 1 shl 24 + 127 |
je .loopback |
; Update stats (and validate device ptr) |
call NET_ptr_to_num |
cmp edi,-1 |
je .dump |
inc [ICMP_PACKETS_RX + 4*edi] |
inc [ICMP_PACKETS_TX + 4*edi] |
; exchange dest and source address in IP header |
; 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-2 |
.loopback: |
add esi, 2 |
push [esi + IPv4_header.SourceAddress] |
push [esi + IPv4_header.DestinationAddress] |
pop [esi + IPv4_header.SourceAddress] |
pop [esi + IPv4_header.DestinationAddress] |
; Recalculate ip header checksum |
movzx ecx, [esi + IPv4_header.VersionAndIHL] ; Calculate IP Header length by using IHL field |
and ecx, 0x0f |
shl cx, 2 |
mov edi, ecx ; IP header length |
mov eax, edx ; ICMP packet start addr |
push esi ; Calculate the IP checksum |
xor edx, edx ; |
call checksum_1 ; |
call checksum_2 ; |
pop esi ; |
mov [esi + IPv4_header.HeaderChecksum], dx ; |
; Recalculate ICMP CheckSum |
movzx ecx, [esi + IPv4_header.TotalLength] ; Find length of IP Packet |
xchg ch, cl ; |
sub ecx, edi ; IP packet length - IP header length = ICMP packet length |
mov esi, eax ; Calculate ICMP checksum |
xor edx, edx ; |
call checksum_1 ; |
call checksum_2 ; |
mov [eax + ICMP_header.Checksum], dx ; |
; Transmit the packet (notice that packet ptr and packet size have been on stack since start of the procedure!) |
call [ebx + NET_DEVICE.transmit] |
ret |
.check_sockets: |
; Look for an open ICMP socket |
mov esi, [edi] ; ipv4 source address |
mov eax, net_sockets |
.try_more: |
; mov , [edx + ICMP_header.Identifier] |
.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 |
cmp [eax + IP_SOCKET.RemoteIP], esi |
jne .next_socket |
; cmp [eax + ICMP_SOCKET.Identifier], |
; jne .next_socket |
; call IPv4_dest_to_dev |
; cmp edi,-1 |
; je .dump |
; inc [ICMP_PACKETS_RX+edi] |
DEBUGF 1,"socket=%x\n", eax |
pusha |
lea ecx, [eax + SOCKET.mutex] |
call mutex_lock |
popa |
mov esi, edx |
jmp SOCKET_input |
.checksum_mismatch: |
DEBUGF 1,"checksum mismatch\n" |
.dump: |
DEBUGF 1,"ICMP_input: dumping\n" |
call kernel_free |
add esp, 4 ; pop (balance stack) |
ret |
;----------------------------------------------------------------- |
; |
; ICMP_output |
; |
; IN: eax = dest ip |
; ebx = source ip |
; ecx = data length |
; dh = type |
; dl = code |
; esi = data offset |
; edi = identifier shl 16 + sequence number |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_output: |
DEBUGF 1,"Creating ICMP Packet\n" |
push esi edi dx |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
add ecx, sizeof.ICMP_header |
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL |
call IPv4_output |
jz .exit |
DEBUGF 1,"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 1,"Sending ICMP Packet\n" |
call [ebx + NET_DEVICE.transmit] |
ret |
.exit: |
DEBUGF 1,"Creating ICMP Packet failed\n" |
add esp, 2*4 + 2 |
ret |
;----------------------------------------------------------------- |
; |
; ICMP_output |
; |
; IN: eax = socket ptr |
; ecx = data length |
; esi = data offset |
; |
;----------------------------------------------------------------- |
align 4 |
ICMP_output_raw: |
DEBUGF 1,"Creating ICMP Packet for socket %x, data ptr=%x\n", eax, edx |
push edx |
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL |
mov edx, [eax + IP_SOCKET.LocalIP] |
mov eax, [eax + IP_SOCKET.RemoteIP] |
call IPv4_output |
jz .exit |
pop esi |
push edx |
push eax |
push edi ecx |
DEBUGF 1,"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 1,"Sending ICMP Packet\n" |
call [ebx + NET_DEVICE.transmit] |
ret |
.exit: |
DEBUGF 1,"Creating ICMP Packet failed\n" |
add esp, 4 |
ret |
;----------------------------------------------------------------- |
; |
; ICMP_API |
; |
; This function is called by system function 75 |
; |
; IN: subfunction number in bl |
; device number in bh |
; ecx, edx, .. depends on subfunction |
; |
; OUT: |
; |
;----------------------------------------------------------------- |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network/queue.inc |
---|
0,0 → 1,100 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. 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 { |
cmp [ptr + queue.size], size ; Check if queue isnt full |
jae failaddr |
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 |
} |
macro get_from_queue ptr, size, entry_size, failaddr { |
cmp [ptr + queue.size], 0 ; any packets queued? |
je failaddr |
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 |
} |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/network |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/const.inc |
---|
0,0 → 1,693 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
dpl0 equ 10010000b ; data read dpl0 |
drw0 equ 10010010b ; data read/write dpl0 |
drw3 equ 11110010b ; data read/write dpl3 |
cpl0 equ 10011010b ; code read dpl0 |
cpl3 equ 11111010b ; code read dpl3 |
D32 equ 01000000b ; 32bit segment |
G32 equ 10000000b ; page gran |
;;;;;;;;;;;;cpu_caps flags;;;;;;;;;;;;;;;; |
CPU_386 equ 3 |
CPU_486 equ 4 |
CPU_PENTIUM equ 5 |
CPU_P6 equ 6 |
CPU_PENTIUM4 equ 0x0F |
CAPS_FPU equ 00 ;on-chip x87 floating point unit |
CAPS_VME equ 01 ;virtual-mode enhancements |
CAPS_DE equ 02 ;debugging extensions |
CAPS_PSE equ 03 ;page-size extensions |
CAPS_TSC equ 04 ;time stamp counter |
CAPS_MSR equ 05 ;model-specific registers |
CAPS_PAE equ 06 ;physical-address extensions |
CAPS_MCE equ 07 ;machine check exception |
CAPS_CX8 equ 08 ;CMPXCHG8B instruction |
CAPS_APIC equ 09 ;on-chip advanced programmable |
; interrupt controller |
; 10 ;unused |
CAPS_SEP equ 11 ;SYSENTER and SYSEXIT instructions |
CAPS_MTRR equ 12 ;memory-type range registers |
CAPS_PGE equ 13 ;page global extension |
CAPS_MCA equ 14 ;machine check architecture |
CAPS_CMOV equ 15 ;conditional move instructions |
CAPS_PAT equ 16 ;page attribute table |
CAPS_PSE36 equ 17 ;page-size extensions |
CAPS_PSN equ 18 ;processor serial number |
CAPS_CLFLUSH equ 19 ;CLFUSH instruction |
CAPS_DS equ 21 ;debug store |
CAPS_ACPI equ 22 ;thermal monitor and software |
;controlled clock supported |
CAPS_MMX equ 23 ;MMX instructions |
CAPS_FXSR equ 24 ;FXSAVE and FXRSTOR instructions |
CAPS_SSE equ 25 ;SSE instructions |
CAPS_SSE2 equ 26 ;SSE2 instructions |
CAPS_SS equ 27 ;self-snoop |
CAPS_HTT equ 28 ;hyper-threading technology |
CAPS_TM equ 29 ;thermal monitor supported |
CAPS_IA64 equ 30 ;IA64 capabilities |
CAPS_PBE equ 31 ;pending break enable |
;ecx |
CAPS_SSE3 equ 32 ;SSE3 instructions |
; 33 |
; 34 |
CAPS_MONITOR equ 35 ;MONITOR/MWAIT instructions |
CAPS_DS_CPL equ 36 ; |
CAPS_VMX equ 37 ;virtual mode extensions |
; 38 ; |
CAPS_EST equ 39 ;enhansed speed step |
CAPS_TM2 equ 40 ;thermal monitor2 supported |
; 41 |
CAPS_CID equ 42 ; |
; 43 |
; 44 |
CAPS_CX16 equ 45 ;CMPXCHG16B instruction |
CAPS_xTPR equ 46 ; |
; |
;reserved |
; |
;ext edx /ecx |
CAPS_SYSCAL equ 64 ; |
CAPS_XD equ 65 ;execution disable |
CAPS_FFXSR equ 66 ; |
CAPS_RDTSCP equ 67 ; |
CAPS_X64 equ 68 ; |
CAPS_3DNOW equ 69 ; |
CAPS_3DNOWEXT equ 70 ; |
CAPS_LAHF equ 71 ; |
CAPS_CMP_LEG equ 72 ; |
CAPS_SVM equ 73 ;secure virual machine |
CAPS_ALTMOVCR8 equ 74 ; |
; CPU MSR names |
MSR_SYSENTER_CS equ 0x174 |
MSR_SYSENTER_ESP equ 0x175 |
MSR_SYSENTER_EIP equ 0x176 |
MSR_AMD_EFER equ 0xC0000080 ; Extended Feature Enable Register |
MSR_AMD_STAR equ 0xC0000081 ; SYSCALL/SYSRET Target Address Register |
CR0_PE equ 0x00000001 ;protected mode |
CR0_MP equ 0x00000002 ;monitor fpu |
CR0_EM equ 0x00000004 ;fpu emulation |
CR0_TS equ 0x00000008 ;task switch |
CR0_ET equ 0x00000010 ;extension type hardcoded to 1 |
CR0_NE equ 0x00000020 ;numeric error |
CR0_WP equ 0x00010000 ;write protect |
CR0_AM equ 0x00040000 ;alignment check |
CR0_NW equ 0x20000000 ;not write-through |
CR0_CD equ 0x40000000 ;cache disable |
CR0_PG equ 0x80000000 ;paging |
CR4_VME equ 0x0001 |
CR4_PVI equ 0x0002 |
CR4_TSD equ 0x0004 |
CR4_DE equ 0x0008 |
CR4_PSE equ 0x0010 |
CR4_PAE equ 0x0020 |
CR4_MCE equ 0x0040 |
CR4_PGE equ 0x0080 |
CR4_PCE equ 0x0100 |
CR4_OSFXSR equ 0x0200 |
CR4_OSXMMEXPT equ 0x0400 |
SSE_IE equ 0x0001 |
SSE_DE equ 0x0002 |
SSE_ZE equ 0x0004 |
SSE_OE equ 0x0008 |
SSE_UE equ 0x0010 |
SSE_PE equ 0x0020 |
SSE_DAZ equ 0x0040 |
SSE_IM equ 0x0080 |
SSE_DM equ 0x0100 |
SSE_ZM equ 0x0200 |
SSE_OM equ 0x0400 |
SSE_UM equ 0x0800 |
SSE_PM equ 0x1000 |
SSE_FZ equ 0x8000 |
SSE_INIT equ (SSE_IM+SSE_DM+SSE_ZM+SSE_OM+SSE_UM+SSE_PM) |
IRQ_PIC equ 0 |
IRQ_APIC equ 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 |
OS_BASE equ 0x80000000 |
window_data equ (OS_BASE+0x0001000) |
CURRENT_TASK equ (OS_BASE+0x0003000) |
TASK_COUNT equ (OS_BASE+0x0003004) |
TASK_BASE equ (OS_BASE+0x0003010) |
TASK_DATA equ (OS_BASE+0x0003020) |
TASK_EVENT equ (OS_BASE+0x0003020) |
mouseunder equ (OS_BASE+0x0006900) |
CDDataBuf equ (OS_BASE+0x0007000) |
FLOPPY_BUFF equ (OS_BASE+0x0008000) |
ACTIVE_PROC_STACK equ (OS_BASE+0x000A400) ;unused |
idts equ (OS_BASE+0x000B100) |
WIN_STACK equ (OS_BASE+0x000C000) |
WIN_POS equ (OS_BASE+0x000C400) |
FDD_BUFF equ (OS_BASE+0x000D000) |
;unused ? only one reference |
ENABLE_TASKSWITCH equ (OS_BASE+0x000E000) |
PUTPIXEL equ (OS_BASE+0x000E020) |
GETPIXEL equ (OS_BASE+0x000E024) |
;unused ? only one reference |
BANK_SWITCH equ (OS_BASE+0x000E030) |
;unused ? store mousepointer |
MOUSE_PICTURE equ (OS_BASE+0x000F200) |
;MOUSE_VISIBLE equ (OS_BASE+0x000F204) |
WIN_TEMP_XY equ (OS_BASE+0x000F300) |
KEY_COUNT equ (OS_BASE+0x000F400) |
KEY_BUFF equ (OS_BASE+0x000F401) |
BTN_COUNT equ (OS_BASE+0x000F500) |
BTN_BUFF equ (OS_BASE+0x000F501) |
CPU_FREQ equ (OS_BASE+0x000F600) |
;unused ? no active references |
MOUSE_PORT equ (OS_BASE+0x000F604) |
;unused |
PS2_CHUNK equ (OS_BASE+0x000FB00) |
MOUSE_SCROLL_H equ (OS_BASE+0x000FB08) |
MOUSE_X equ (OS_BASE+0x000FB0A) |
MOUSE_Y equ (OS_BASE+0x000FB0C) |
MOUSE_SCROLL_V equ (OS_BASE+0x000FB0E) |
MOUSE_COLOR_MEM equ (OS_BASE+0x000FB10) |
COLOR_TEMP equ (OS_BASE+0x000FB30) |
BTN_DOWN equ (OS_BASE+0x000FB40) |
MOUSE_DOWN equ (OS_BASE+0x000FB44) |
X_UNDER equ (OS_BASE+0x000FB4A) |
Y_UNDER equ (OS_BASE+0x000FB4C) |
ScreenBPP equ (OS_BASE+0x000FBF1) |
;unused ? only one reference |
MOUSE_BUFF_COUNT equ (OS_BASE+0x000FCFF) |
Screen_Max_X equ (OS_BASE+0x000FE00) |
Screen_Max_Y equ (OS_BASE+0x000FE04) |
BytesPerScanLine equ (OS_BASE+0x000FE08) |
SCR_MODE equ (OS_BASE+0x000FE0C) |
LFBAddress equ (OS_BASE+0x000FE80) |
BTN_ADDR equ (OS_BASE+0x000FE88) |
MEM_AMOUNT equ (OS_BASE+0x000FE8C) |
SYS_SHUTDOWN equ (OS_BASE+0x000FF00) |
TASK_ACTIVATE equ (OS_BASE+0x000FF01) |
REDRAW_BACKGROUND equ (OS_BASE+0x000FFF0) |
BANK_RW equ (OS_BASE+0x000FFF2) |
MOUSE_BACKGROUND equ (OS_BASE+0x000FFF4) |
DONT_DRAW_MOUSE equ (OS_BASE+0x000FFF5) |
DONT_SWITCH equ (OS_BASE+0x000FFFF) |
TMP_STACK_TOP equ 0x006CC00 |
sys_pgdir equ (OS_BASE+0x006F000) |
DRIVE_DATA equ (OS_BASE+0x0070000) |
SLOT_BASE equ (OS_BASE+0x0080000) |
;unused |
TMP_BUFF equ (OS_BASE+0x0090000) |
VGABasePtr equ (OS_BASE+0x00A0000) |
RAMDISK equ (OS_BASE+0x0100000) |
RAMDISK_FAT equ (OS_BASE+0x0280000) |
FLOPPY_FAT equ (OS_BASE+0x0282000) |
CLEAN_ZONE equ 0x284000 |
IDE_DMA equ 0x284000 |
BgrAuxTable equ (OS_BASE+0x0298000) |
; unused? |
SB16Buffer equ (OS_BASE+0x02A0000) |
SB16_Status equ (OS_BASE+0x02B0000) |
BUTTON_INFO equ (OS_BASE+0x02B3FEE) |
BPSLine_calc_area equ (OS_BASE+0x02C4000) |
d_width_calc_area equ (OS_BASE+0x02CA000) |
RESERVED_PORTS equ (OS_BASE+0x02D0000) |
BOOT_VAR equ (OS_BASE+0x02E0000) |
stack_data_start equ (OS_BASE+0x02F0000) |
eth_data_start equ (OS_BASE+0x02F0000) |
stack_data equ (OS_BASE+0x02F4000) |
stack_data_end equ (OS_BASE+0x030ffff) |
resendQ equ (OS_BASE+0x0310000) |
skin_data equ (OS_BASE+0x0318000) |
draw_data equ (OS_BASE+0x0320000) |
BgrDrawMode equ (OS_BASE+0x0323FF4) |
BgrDataWidth equ (OS_BASE+0x0323FF8) |
BgrDataHeight equ (OS_BASE+0x0323FFC) |
sys_pgmap equ (OS_BASE+0x0324000) |
UPPER_KERNEL_PAGES equ (OS_BASE+0x0400000) |
virtual at (OS_BASE+0x05FFF80) |
tss TSS |
end virtual |
HEAP_BASE equ (OS_BASE+0x0800000) |
HEAP_MIN_SIZE equ 0x01000000 |
page_tabs equ 0xFDC00000 |
app_page_tabs equ 0xFDC00000 |
kernel_tabs equ (page_tabs+ (OS_BASE shr 10)) ;0xFDE00000 |
master_tab equ (page_tabs+ (page_tabs shr 10)) ;0xFDFF70000 |
LFB_BASE equ 0xFE000000 |
new_app_base equ 0; |
twdw equ 0x2000 ;(CURRENT_TASK-window_data) |
std_application_base_address equ new_app_base |
RING0_STACK_SIZE equ (0x2000 - 512) ;512 áàéò äëÿ êîíòåêñòà FPU |
REG_SS equ (RING0_STACK_SIZE-4) |
REG_APP_ESP equ (RING0_STACK_SIZE-8) |
REG_EFLAGS equ (RING0_STACK_SIZE-12) |
REG_CS equ (RING0_STACK_SIZE-16) |
REG_EIP equ (RING0_STACK_SIZE-20) |
REG_EAX equ (RING0_STACK_SIZE-24) |
REG_ECX equ (RING0_STACK_SIZE-28) |
REG_EDX equ (RING0_STACK_SIZE-32) |
REG_EBX equ (RING0_STACK_SIZE-36) |
REG_ESP equ (RING0_STACK_SIZE-40) ;RING0_STACK_SIZE-20 |
REG_EBP equ (RING0_STACK_SIZE-44) |
REG_ESI equ (RING0_STACK_SIZE-48) |
REG_EDI equ (RING0_STACK_SIZE-52) |
REG_RET equ (RING0_STACK_SIZE-56) ;irq0.return |
PG_UNMAP equ 0x000 |
PG_MAP equ 0x001 |
PG_WRITE equ 0x002 |
PG_SW equ 0x003 |
PG_USER equ 0x005 |
PG_UW equ 0x007 |
PG_NOCACHE equ 0x018 |
PG_LARGE equ 0x080 |
PG_GLOBAL equ 0x100 |
PG_SHARED equ 0x200 |
;;;;;;;;;;;boot time variables |
BOOT_BPP equ 0x9000 ;byte bits per pixel |
BOOT_PITCH equ 0x9001 ;word scanline length |
BOOT_VESA_MODE equ 0x9008 ;word vesa video mode |
BOOT_X_RES equ 0x900A ;word X res |
BOOT_Y_RES equ 0x900C ;word Y res |
;;BOOT_MOUSE_PORT equ 0x9010 ;byte mouse port - not used |
BOOT_BANK_SW equ 0x9014 ;dword Vesa 1.2 pm bank switch |
BOOT_LFB equ 0x9018 ;dword Vesa 2.0 LFB address |
BOOT_MTRR equ 0x901C ;byte 0 or 1 : enable MTRR graphics acceleration |
BOOT_LOG equ 0x901D ;byte not used anymore (0 or 1 : enable system log display) |
;BOOT_DIRECT_LFB equ 0x901E ;byte 0 or 1 : enable direct lfb write, paging disabled |
BOOT_DMA equ 0x901F ; |
BOOT_PCI_DATA equ 0x9020 ;8bytes pci data |
BOOT_VRR equ 0x9030 ;byte VRR start enabled 1, 2-no |
BOOT_IDE_BASE_ADDR equ 0x9031 ;word IDEContrRegsBaseAddr |
BOOT_MEM_AMOUNT equ 0x9034 ;dword memory amount |
BOOT_APM_ENTRY equ 0x9040 |
BOOT_APM_VERSION equ 0x9044 |
BOOT_APM_FLAGS equ 0x9046 ;unused |
BOOT_APM_CODE_32 equ 0x9050 |
BOOT_APM_CODE_16 equ 0x9052 |
BOOT_APM_DATA_16 equ 0x9054 |
TMP_FILE_NAME equ 0 |
TMP_CMD_LINE equ 1024 |
TMP_ICON_OFFS equ 1280 |
EVENT_REDRAW equ 0x00000001 |
EVENT_KEY equ 0x00000002 |
EVENT_BUTTON equ 0x00000004 |
EVENT_BACKGROUND equ 0x00000010 |
EVENT_MOUSE equ 0x00000020 |
EVENT_IPC equ 0x00000040 |
EVENT_NETWORK equ 0x00000080 |
EVENT_DEBUG equ 0x00000100 |
EVENT_NETWORK2 equ 0x00000200 |
EVENT_EXTENDED equ 0x00000400 |
EV_INTR equ 1 |
struct THR_DATA |
rb (8192-512) |
; pl0_stack |
fpu_state rb 512 |
tls_page rb 4096 |
pdbr rb 4096 |
ends |
virtual at (OS_BASE-sizeof.THR_DATA) |
thr_data THR_DATA |
end virtual |
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 |
APP_OBJ_OFFSET equ 48 |
APP_EV_OFFSET equ 40 |
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 display_t |
x dd ? |
y dd ? |
width dd ? |
height dd ? |
bpp dd ? |
vrefresh dd ? |
pitch dd ? |
lfb 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 ? |
ends |
struct BOOT_DATA |
bpp dd ? |
scanline dd ? |
vesa_mode dd ? |
x_res dd ? |
y_res dd ? |
mouse_port dd ? |
bank_switch dd ? |
lfb dd ? |
vesa_mem dd ? |
log dd ? |
direct_lfb dd ? |
pci_data dd ? |
dd ? |
vrr dd ? |
ide_base dd ? |
mem_amount dd ? |
pages_count dd ? |
pagemap_size dd ? |
kernel_max dd ? |
kernel_pages dd ? |
kernel_tables dd ? |
cpu_vendor dd ? |
dd ? |
dd ? |
cpu_sign dd ? |
cpu_info dd ? |
cpu_caps dd ? |
dd ? |
dd ? |
ends |
struct LHEAD |
next dd ? ;next object in list |
prev dd ? ;prev object in list |
ends |
struct MUTEX |
lhead LHEAD |
count dd ? |
ends |
struct PCIDEV |
bk dd ? |
fd dd ? |
vendor_device_id dd ? |
class dd ? |
devfn db ? |
bus 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 |
DRV_ENTRY equ 1 |
DRV_EXIT equ -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 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 |
ends |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/bus/pci/pci32.inc |
---|
0,0 → 1,724 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 equ 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_VAR+0x9022] |
ret |
pci_fn_1: |
; PCI function 1: get last bus in AL |
mov al, [BOOT_VAR+0x9021] |
ret |
pci_fn_2: |
; PCI function 2: get pci access mechanism |
mov al, [BOOT_VAR+0x9020] |
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_VAR+0x9020], 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 |
; get current state |
mov dx, 0xcf8 |
in eax, dx |
push eax |
; 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 |
jmp pci_fin_read1 |
pci_fin_read1: |
; restore configuration control |
xchg eax, [esp] |
mov dx, 0xcf8 |
out dx, eax |
pop eax |
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 |
push eax |
;store current state of config space |
mov dx, 0xcf8 |
in al, dx |
mov ah, al |
mov dl, 0xfa |
in al, dx |
xchg eax, [esp] |
; 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 |
; jmp pci_fin_read2 |
pci_fin_read2: |
; restore configuration space |
xchg eax, [esp] |
mov dx, 0xcfa |
out dx, al |
mov dl, 0xf8 |
mov al, ah |
out dx, al |
pop eax |
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_VAR+0x9020], 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 |
; get current state into ecx |
mov dx, 0xcf8 |
in eax, dx |
push eax |
; 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 |
jmp pci_fin_write1 |
pci_fin_write1: |
; restore configuration control |
pop eax |
mov dl, 0xf8 |
out dx, eax |
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 |
push eax |
;store current state of config space |
mov dx, 0xcf8 |
in al, dx |
mov ah, al |
mov dl, 0xfa |
in al, dx |
xchg eax, [esp] |
; 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 |
jmp pci_fin_write2 |
pci_fin_write2: |
; restore configuration space |
pop eax |
mov dx, 0xcfa |
out dx, al |
mov dl, 0xf8 |
mov al, ah |
out dx, al |
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_VAR + 0x9020] |
mov bx, [BOOT_VAR + 0x9022] |
mov cl, [BOOT_VAR + 0x9021] |
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 |
push sizeof.PCIDEV |
pop eax |
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 word [edi+PCIDEV.devfn], ax |
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_VAR+0x9021] |
jbe .loop |
.nomemory: |
leave |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/bus/pci/PCIe.inc |
---|
0,0 → 1,119 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2011. 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: 1463 $ |
;*************************************************************************** |
; 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 equ 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 >>>>>>>>> |
/kernel/branches/net/bus/pci/pci16.inc |
---|
0,0 → 1,51 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:0x9020], 1;default mechanism:1 |
mov ax, 0xb101 |
int 0x1a |
or ah, ah |
jnz pci16skip |
mov [es:0x9021], cl;last PCI bus in system |
mov [es:0x9022], bx |
mov [es:0x9024], 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:0x9020], 2; if (al&3)==2 => mechanism 2 |
pci16skip: |
mov ax, 0x1000 |
mov es, ax |
popad |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/bus |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/core/heap.inc |
---|
0,0 → 1,1537 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
FREE_BLOCK equ 4 |
USED_BLOCK equ 8 |
DONT_FREE_BLOCK equ 10h |
block_next equ MEM_BLOCK.next_block |
block_prev equ MEM_BLOCK.prev_block |
list_fd equ MEM_BLOCK.list.next |
list_bk equ MEM_BLOCK.list.prev |
block_base equ MEM_BLOCK.base |
block_size equ MEM_BLOCK.size |
block_flags equ MEM_BLOCK.flags |
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+block_base] |
mov ebx, [esi+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+block_flags], USED_BLOCK |
mov eax, [esi+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+list_fd] |
cmp esi, ebx |
je .fail |
cmp eax, [esi+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+block_flags], USED_BLOCK |
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 USED_BLOCK |
;+4096*MEM_BLOCK.sizeof free space FREE_BLOCK |
;HEAP_BASE heap_descriptors USED_BLOCK |
; |
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 |
mov ecx, 32 |
mov edx, eax |
mov edi, HEAP_BASE |
.l1: |
stdcall map_page, edi, edx, PG_SW |
add edi, 0x1000 |
add edx, 0x1000 |
dec ecx |
jnz .l1 |
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+block_next], ebx |
mov [edi+block_prev], eax |
mov [edi+list_fd], eax |
mov [edi+list_bk], eax |
mov [edi+block_base], HEAP_BASE |
mov [edi+block_size], 4096*sizeof.MEM_BLOCK |
mov [edi+block_flags], USED_BLOCK |
mov [ecx+block_next], eax |
mov [ecx+block_prev], ebx |
mov [ecx+list_fd], eax |
mov [ecx+list_bk], eax |
mov [ecx+block_base], eax |
mov [ecx+block_size], eax |
mov [ecx+block_flags], USED_BLOCK |
mov [ebx+block_next], ecx |
mov [ebx+block_prev], edi |
mov [ebx+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+block_size], ecx |
mov [ebx+block_flags], FREE_BLOCK |
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 [eax-sizeof.MEM_BLOCK], dword 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+list_fd] |
cmp edi, ecx |
je .err |
cmp eax, [edi+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 |
mov ecx, heap_mutex |
call mutex_lock |
mov eax, [size] |
call get_small_block ; eax |
test edi, edi |
jz .error_unlock |
cmp [edi+block_flags], FREE_BLOCK |
jne .error_unlock |
mov [block_ind], ebx ;index of allocated block |
mov eax, [edi+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+block_next], edi |
mov eax, [edi+block_prev] |
mov [esi+block_prev], eax |
mov [edi+block_prev], esi |
mov [esi+list_fd], 0 |
mov [esi+list_bk], 0 |
mov [eax+block_next], esi |
mov ebx, [edi+block_base] |
mov [esi+block_base], ebx |
mov edx, [size] |
mov [esi+block_size], edx |
add [edi+block_base], edx |
sub [edi+block_size], edx |
mov eax, [edi+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 |
mov ecx, heap_mutex |
call mutex_unlock |
mov eax, [esi+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: |
mov ecx, heap_mutex |
call mutex_unlock |
.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 |
mov ecx, heap_mutex |
call mutex_lock |
mov eax, [base] |
call md.del_from_used |
test esi, esi |
jz .fail |
mov eax, [esi+block_size] |
add [heap_free], eax |
mov edi, [esi+block_next] |
cmp [edi+block_flags], FREE_BLOCK |
jne .prev |
list_del edi |
mov edx, [edi+block_next] |
mov [esi+block_next], edx |
mov [edx+block_prev], esi |
mov ecx, [edi+block_size] |
add [esi+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+block_prev] |
cmp [edi+block_flags], FREE_BLOCK |
jne .insert |
mov edx, [esi+block_next] |
mov [edi+block_next], edx |
mov [edx+block_prev], edi |
mov eax, esi |
call free_mem_block |
mov ecx, [edi+block_size] |
mov eax, [esi+block_size] |
add eax, ecx |
mov [edi+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: |
mov ecx, heap_mutex |
call mutex_unlock |
xor eax, eax |
not eax |
ret |
.insert: |
mov [esi+block_flags], FREE_BLOCK |
mov eax, [esi+block_size] |
calc_index eax |
mov edi, esi |
jmp .add_block |
.fail: |
mov ecx, heap_mutex |
call mutex_unlock |
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 |
test eax, eax |
jz .err |
mov [lin_addr], eax |
mov ecx, [pages_count] |
mov edx, eax |
mov ebx, ecx |
shr ecx, 3 |
jz .next |
and ebx, not 7 |
push ebx |
stdcall alloc_pages, ebx |
pop ecx ; yes ecx!!! |
and eax, eax |
jz .err |
mov edi, eax |
mov edx, [lin_addr] |
@@: |
stdcall map_page, edx, edi, dword PG_SW |
add edx, 0x1000 |
add edi, 0x1000 |
dec ecx |
jnz @B |
.next: |
mov ecx, [pages_count] |
and ecx, 7 |
jz .end |
@@: |
push ecx |
call alloc_page |
pop ecx |
test eax, eax |
jz .err |
stdcall map_page, edx, eax, dword PG_SW |
add edx, 0x1000 |
dec ecx |
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 |
mov ecx, heap_mutex |
call mutex_lock |
mov eax, [base] |
call md.find_used |
mov ecx, heap_mutex |
cmp [esi+block_flags], USED_BLOCK |
jne .fail |
call mutex_unlock |
mov eax, [esi+block_base] |
mov ecx, [esi+block_size] |
shr ecx, 12 |
call release_pages ;eax, ecx |
stdcall free_kernel_space, [base] |
pop esi ebx |
ret |
.fail: |
call mutex_unlock |
xor eax, eax |
pop esi ebx |
ret |
endp |
restore block_next |
restore block_prev |
restore block_list |
restore block_base |
restore block_size |
restore block_flags |
;;;;;;;;;;;;;; USER ;;;;;;;;;;;;;;;;; |
HEAP_TOP equ 0x80000000 |
align 4 |
proc init_heap |
mov ebx, [current_slot] |
mov eax, [ebx+APPDATA.heap_top] |
test eax, eax |
jz @F |
sub eax, [ebx+APPDATA.heap_base] |
sub eax, 4096 |
ret |
@@: |
mov esi, [ebx+APPDATA.mem_size] |
add esi, 4095 |
and esi, not 4095 |
mov [ebx+APPDATA.mem_size], esi |
mov eax, HEAP_TOP |
mov [ebx+APPDATA.heap_base], esi |
mov [ebx+APPDATA.heap_top], eax |
sub eax, esi |
shr esi, 10 |
mov ecx, eax |
sub eax, 4096 |
or ecx, FREE_BLOCK |
mov [page_tabs+esi], ecx |
ret |
endp |
align 4 |
proc user_alloc stdcall, alloc_size:dword |
push ebx |
push esi |
push edi |
mov ecx, [alloc_size] |
add ecx, (4095+4096) |
and ecx, not 4095 |
mov ebx, [current_slot] |
mov esi, dword [ebx+APPDATA.heap_base] ; heap_base |
mov edi, dword [ebx+APPDATA.heap_top] ; heap_top |
l_0: |
cmp esi, edi |
jae m_exit |
mov ebx, esi |
shr ebx, 12 |
mov eax, [page_tabs+ebx*4] |
test al, FREE_BLOCK |
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, FREE_BLOCK |
shr edx, 12 |
mov [page_tabs+edx*4], eax |
@@: |
or ecx, USED_BLOCK |
mov [page_tabs+ebx*4], ecx |
shr ecx, 12 |
inc ebx |
dec ecx |
jz .no |
@@: |
mov dword [page_tabs+ebx*4], 2 |
inc ebx |
dec ecx |
jnz @B |
.no: |
mov edx, [current_slot] |
mov ebx, [alloc_size] |
add ebx, 0xFFF |
and ebx, not 0xFFF |
add ebx, [edx+APPDATA.mem_size] |
call update_mem_size |
lea eax, [esi+4096] |
pop edi |
pop esi |
pop ebx |
ret |
test_used: |
test al, USED_BLOCK |
jz m_exit |
and eax, 0xFFFFF000 |
m_next: |
add esi, eax |
jmp l_0 |
m_exit: |
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_slot] |
mov edx, [address] |
and edx, not 0xFFF |
mov [address], edx |
sub edx, 0x1000 |
jb .error |
mov esi, [ebx+APPDATA.heap_base] |
mov edi, [ebx+APPDATA.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: |
xor eax, eax |
pop edi |
pop esi |
pop ebx |
ret |
.found: |
test al, FREE_BLOCK |
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, FREE_BLOCK |
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, USED_BLOCK |
mov [page_tabs+ebx*4], eax |
shr eax, 12 |
dec eax |
jz .second_nofill |
inc ebx |
.fill: |
mov dword [page_tabs+ebx*4], 2 |
inc ebx |
dec eax |
jnz .fill |
.second_nofill: |
sub ecx, edx |
jz .nothird |
or cl, FREE_BLOCK |
mov [page_tabs+ebx*4], ecx |
.nothird: |
mov edx, [current_slot] |
mov ebx, [alloc_size] |
add ebx, 0xFFF |
and ebx, not 0xFFF |
add ebx, [edx+APPDATA.mem_size] |
call update_mem_size |
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 .exit |
push ebx |
xor ebx, ebx |
shr esi, 12 |
mov eax, [page_tabs+(esi-1)*4] |
test al, USED_BLOCK |
jz .cantfree |
test al, DONT_FREE_BLOCK |
jnz .cantfree |
and eax, not 4095 |
mov ecx, eax |
or al, FREE_BLOCK |
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_slot] |
mov esi, dword [edx+APPDATA.heap_base] |
mov edi, dword [edx+APPDATA.heap_top] |
sub ebx, [edx+APPDATA.mem_size] |
neg ebx |
call update_mem_size |
call user_normalize |
pop edi |
pop ebx |
pop esi |
ret |
.exit: |
xor eax, eax |
inc eax |
pop esi |
ret |
.cantfree: |
xor eax, eax |
pop ebx |
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, USED_BLOCK |
jz .error |
test al, DONT_FREE_BLOCK |
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 ? |
.unmap: |
mov eax, [edx] ; get page addres |
test al, 1 ; page mapped ? |
jz @F |
test eax, PG_SHARED ; page shared ? |
jnz @F |
mov [page_tabs+edx*4], dword 2 |
; mark page as reserved |
invlpg [ebx] ; when we start using |
call free_page ; empty c-o-w page instead this ? |
@@: |
add ebx, 4096 |
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, USED_BLOCK |
jz .test_free |
shr eax, 12 |
add esi, eax |
jmp @B |
.test_free: |
test al, FREE_BLOCK |
jz .err |
mov edx, eax |
shr edx, 12 |
add edx, esi |
cmp edx, edi |
jae .exit |
mov ebx, [page_tabs+edx*4] |
test bl, USED_BLOCK |
jz .next_free |
shr ebx, 12 |
add edx, ebx |
mov esi, edx |
jmp @B |
.next_free: |
test bl, FREE_BLOCK |
jz .err |
and dword [page_tabs+edx*4], 0 |
add eax, ebx |
and eax, not 4095 |
or eax, FREE_BLOCK |
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 |
lea ecx, [eax - 0x1000] |
shr ecx, 12 |
mov edx, [page_tabs+ecx*4] |
test dl, USED_BLOCK |
jnz @f |
; attempt to realloc invalid pointer |
.ret0: |
pop edx ecx |
xor eax, eax |
ret |
@@: |
test dl, DONT_FREE_BLOCK |
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_slot] |
mov ebx, [APPDATA.mem_size+edx] |
sub ebx, eax |
add ebx, 0x1000 |
or al, FREE_BLOCK |
mov [page_tabs+ecx*4], eax |
push esi edi |
mov esi, [APPDATA.heap_base+edx] |
mov edi, [APPDATA.heap_top+edx] |
call update_mem_size |
call user_normalize |
pop edi esi |
jmp .ret0 ; all freed |
.nofreeall: |
sub edx, ecx |
shl ebx, 12 |
or ebx, USED_BLOCK |
xchg [page_tabs+ecx*4], ebx |
shr ebx, 12 |
sub ebx, edx |
push ebx ecx edx |
mov edx, [current_slot] |
shl ebx, 12 |
sub ebx, [APPDATA.mem_size+edx] |
neg ebx |
call update_mem_size |
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_slot] |
mov esi, [APPDATA.heap_top+esi] |
shr esi, 12 |
@@: |
cmp edx, esi |
jae .merge_done |
mov eax, [page_tabs+edx*4] |
test al, USED_BLOCK |
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, FREE_BLOCK |
mov [page_tabs+ecx*4], ebx |
.ret: |
pop eax edx ecx |
ret |
.realloc_add: |
; get some additional memory |
mov eax, [current_slot] |
mov eax, [APPDATA.heap_top+eax] |
shr eax, 12 |
cmp edx, eax |
jae .cant_inplace |
mov eax, [page_tabs+edx*4] |
test al, FREE_BLOCK |
jz .cant_inplace |
shr eax, 12 |
add eax, edx |
sub eax, ebx |
jb .cant_inplace |
jz @f |
shl eax, 12 |
or al, FREE_BLOCK |
mov [page_tabs+ebx*4], eax |
@@: |
mov eax, ebx |
sub eax, ecx |
shl eax, 12 |
or al, USED_BLOCK |
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_slot] |
shl ebx, 12 |
add ebx, [APPDATA.mem_size+edx] |
call update_mem_size |
pop eax edx ecx |
ret |
.cant_inplace: |
push esi edi |
mov eax, [current_slot] |
mov esi, [APPDATA.heap_base+eax] |
mov edi, [APPDATA.heap_top+eax] |
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, FREE_BLOCK |
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, FREE_BLOCK |
mov [page_tabs+esi*4], eax |
pop esi |
@@: |
mov eax, ebx |
shl eax, 12 |
or al, USED_BLOCK |
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, FREE_BLOCK |
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_slot] |
shl ebx, 12 |
add ebx, [APPDATA.mem_size+edx] |
call update_mem_size |
pop ebx |
@@: |
mov dword [page_tabs+esi*4], 2 |
inc esi |
dec ebx |
jnz @b |
pop eax edi esi edx ecx |
ret |
if 0 |
align 4 |
proc alloc_dll |
pushf |
cli |
bsf eax, [dll_map] |
jnz .find |
popf |
xor eax, eax |
ret |
.find: |
btr [dll_map], eax |
popf |
shl eax, 5 |
add eax, dll_tab |
ret |
endp |
align 4 |
proc alloc_service |
pushf |
cli |
bsf eax, [srv_map] |
jnz .find |
popf |
xor eax, eax |
ret |
.find: |
btr [srv_map], eax |
popf |
shl eax, 0x02 |
lea eax, [srv_tab+eax+eax*8] ;srv_tab+eax*36 |
ret |
endp |
end if |
;;;;;;;;;;;;;; SHARED ;;;;;;;;;;;;;;;;; |
; 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 equ 5 |
E_ACCESS equ 10 |
E_NOMEM equ 30 |
E_PARAM equ 33 |
SHM_READ equ 0 |
SHM_WRITE equ 1 |
SHM_ACCESS_MASK equ 3 |
SHM_OPEN equ (0 shl 2) |
SHM_OPEN_ALWAYS equ (1 shl 2) |
SHM_CREATE equ (2 shl 2) |
SHM_OPEN_MASK equ (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_TASK] |
shl ebx, 5 |
mov ebx, [CURRENT_TASK+ebx+4] |
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_USER+PG_SHARED |
@@: |
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 |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/peload.inc |
---|
0,0 → 1,341 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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+60] |
stdcall kernel_alloc, [eax+80+edx] |
test eax, eax |
jz .cleanup |
mov [base], eax |
stdcall map_PE, eax, [image] |
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 |
DWORD equ dword |
PTR equ |
align 4 |
map_PE: ;stdcall base:dword, image:dword |
cld |
push ebp |
push edi |
push esi |
push ebx |
sub esp, 60 |
mov ebx, DWORD PTR [esp+84] |
mov ebp, DWORD PTR [esp+80] |
mov edx, ebx |
mov esi, ebx |
add edx, DWORD PTR [ebx+60] |
mov edi, ebp |
mov DWORD PTR [esp+32], edx |
mov ecx, DWORD PTR [edx+84] |
shr ecx, 2 |
rep movsd |
movzx eax, WORD PTR [edx+6] |
mov DWORD PTR [esp+36], 0 |
mov DWORD PTR [esp+16], eax |
jmp L2 |
L3: |
mov eax, DWORD PTR [edx+264] |
test eax, eax |
je L4 |
mov esi, ebx |
mov edi, ebp |
add esi, DWORD PTR [edx+268] |
mov ecx, eax |
add edi, DWORD PTR [edx+260] |
shr ecx, 2 |
rep movsd |
L4: |
mov ecx, DWORD PTR [edx+256] |
add ecx, 4095 |
and ecx, -4096 |
cmp ecx, eax |
jbe L6 |
sub ecx, eax |
add eax, DWORD PTR [edx+260] |
lea edi, [eax+ebp] |
xor eax, eax |
rep stosb |
L6: |
inc DWORD PTR [esp+36] |
add edx, 40 |
L2: |
mov esi, DWORD PTR [esp+16] |
cmp DWORD PTR [esp+36], esi |
jne L3 |
mov edi, DWORD PTR [esp+32] |
cmp DWORD PTR [edi+164], 0 |
je L9 |
mov esi, ebp |
mov ecx, ebp |
sub esi, DWORD PTR [edi+52] |
add ecx, DWORD PTR [edi+160] |
mov eax, esi |
shr eax, 16 |
mov DWORD PTR [esp+12], eax |
jmp L11 |
L12: |
lea ebx, [eax-8] |
xor edi, edi |
shr ebx, 1 |
jmp L13 |
L14: |
movzx eax, WORD PTR [ecx+8+edi*2] |
mov edx, eax |
shr eax, 12 |
and edx, 4095 |
add edx, DWORD PTR [ecx] |
cmp ax, 2 |
je L17 |
cmp ax, 3 |
je L18 |
dec ax |
jne L15 |
mov eax, DWORD PTR [esp+12] |
add WORD PTR [edx+ebp], ax |
L17: |
add WORD PTR [edx+ebp], si |
L18: |
add DWORD PTR [edx+ebp], esi |
L15: |
inc edi |
L13: |
cmp edi, ebx |
jne L14 |
add ecx, DWORD PTR [ecx+4] |
L11: |
mov eax, DWORD PTR [ecx+4] |
test eax, eax |
jne L12 |
L9: |
mov edx, DWORD PTR [esp+32] |
cmp DWORD PTR [edx+132], 0 |
je L20 |
mov eax, ebp |
add eax, DWORD PTR [edx+128] |
mov DWORD PTR [esp+40], 0 |
add eax, 20 |
mov DWORD PTR [esp+56], eax |
L22: |
mov ecx, DWORD PTR [esp+56] |
cmp DWORD PTR [ecx-16], 0 |
jne L23 |
cmp DWORD PTR [ecx-8], 0 |
je L25 |
L23: |
mov edi, DWORD PTR [__exports+32] |
mov esi, DWORD PTR [__exports+28] |
mov eax, DWORD PTR [esp+56] |
mov DWORD PTR [esp+20], edi |
add edi, OS_BASE |
add esi, OS_BASE |
mov DWORD PTR [esp+44], esi |
mov ecx, DWORD PTR [eax-4] |
mov DWORD PTR [esp+48], edi |
mov edx, DWORD PTR [eax-20] |
mov DWORD PTR [esp+52], 0 |
add ecx, ebp |
add edx, ebp |
mov DWORD PTR [esp+24], edx |
mov DWORD PTR [esp+28], ecx |
L26: |
mov esi, DWORD PTR [esp+52] |
mov edi, DWORD PTR [esp+24] |
mov eax, DWORD PTR [edi+esi*4] |
test eax, eax |
je L27 |
test eax, eax |
js L27 |
lea edi, [ebp+eax] |
mov eax, DWORD PTR [esp+28] |
mov DWORD PTR [eax+esi*4], 0 |
lea esi, [edi+2] |
push eax |
push 32 |
movzx eax, WORD PTR [edi] |
mov edx, DWORD PTR [esp+56] |
mov eax, DWORD PTR [edx+eax*4] |
add eax, OS_BASE |
push eax |
push esi |
call strncmp |
pop ebx |
xor ebx, ebx |
test eax, eax |
jne L32 |
jmp L30 |
L33: |
push ecx |
push 32 |
mov ecx, DWORD PTR [esp+28] |
mov eax, DWORD PTR [ecx+OS_BASE+ebx*4] |
add eax, OS_BASE |
push eax |
push esi |
call strncmp |
pop edx |
test eax, eax |
jne L34 |
mov esi, DWORD PTR [esp+44] |
mov edx, DWORD PTR [esp+52] |
mov ecx, DWORD PTR [esp+28] |
mov eax, DWORD PTR [esi+ebx*4] |
add eax, OS_BASE |
mov DWORD PTR [ecx+edx*4], eax |
jmp L36 |
L34: |
inc ebx |
L32: |
cmp ebx, DWORD PTR [__exports+24] |
jb L33 |
L36: |
cmp ebx, DWORD PTR [__exports+24] |
jne L37 |
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 DWORD PTR [esp+40], 1 |
jmp L37 |
L30: |
movzx eax, WORD PTR [edi] |
mov esi, DWORD PTR [esp+44] |
mov edi, DWORD PTR [esp+52] |
mov edx, DWORD PTR [esp+28] |
mov eax, DWORD PTR [esi+eax*4] |
add eax, OS_BASE |
mov DWORD PTR [edx+edi*4], eax |
L37: |
inc DWORD PTR [esp+52] |
jmp L26 |
L27: |
add DWORD PTR [esp+56], 20 |
jmp L22 |
L25: |
xor eax, eax |
cmp DWORD PTR [esp+40], 0 |
jne L40 |
L20: |
mov ecx, DWORD PTR [esp+32] |
mov eax, ebp |
add eax, DWORD PTR [ecx+40] |
L40: |
add esp, 60 |
pop ebx |
pop esi |
pop edi |
pop ebp |
ret 8 |
align 16 |
__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_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 |
\ |
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 |
\ |
mutex_init, 'MutexInit', \ ; gcc fastcall |
mutex_lock, 'MutexLock', \ ; gcc fastcall |
mutex_unlock, 'MutexUnlock', \ ; gcc fastcall |
\ |
get_display, 'GetDisplay', \ |
set_screen, 'SetScreen', \ |
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_free, 'UserFree', \ ; stdcall |
unmap_pages, 'UnmapPages', \ ; eax, ecx |
sys_msg_board_str, 'SysMsgBoardStr', \ |
get_timer_ticks, 'GetTimerTicks', \ |
get_stack_base, 'GetStackBase', \ |
delay_hs, 'Delay', \ ; ebx |
set_mouse_data, 'SetMouseData', \ ; |
set_keyboard_data, 'SetKeyboardData', \ ; gcc fastcall |
timer_hs, 'TimerHs' ; stdcall |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/v86.inc |
---|
0,0 → 1,923 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2007-2012. 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 |
pagedir dd ? |
; translation table: V86 address -> flat linear address |
pages 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 |
; We allocate 4 pages. |
; First is main page directory for V86 mode. |
; Second page: |
; first half (0x800 bytes) is page table for addresses 0 - 0x100000, |
; second half is for V86-to-linear translation. |
; Third and fourth are for I/O permission map. |
push 8000h ; blocks less than 8 pages are discontinuous |
call kernel_alloc |
test eax, eax |
jz .fail2 |
mov [ebx+V86_machine.pagedir], eax |
push edi eax |
mov edi, eax |
add eax, 1800h |
mov [ebx+V86_machine.pages], eax |
; initialize tables |
mov ecx, 2000h/4 |
xor eax, eax |
rep stosd |
mov [ebx+V86_machine.iopm], edi |
dec eax |
mov ecx, 2000h/4 |
rep stosd |
pop eax |
; page directory: first entry is page table... |
mov edi, eax |
add eax, 1000h |
push eax |
call get_pg_addr |
or al, PG_UW |
stosd |
; ...and also copy system page tables |
; thx to Serge, system is located at high addresses |
add edi, (OS_BASE shr 20) - 4 |
push esi |
mov esi, (OS_BASE shr 20) + sys_pgdir |
mov ecx, 0x80000000 shr 22 |
rep movsd |
mov eax, [ebx+V86_machine.pagedir] ;root dir also is |
call get_pg_addr ;used as page table |
or al, PG_SW |
mov [edi-4096+(page_tabs shr 20)], eax |
pop esi |
; now V86 specific: initialize known addresses in first Mb |
pop eax |
; first page - BIOS data (shared between all machines!) |
; physical address = 0 |
; linear address = OS_BASE |
mov dword [eax], 111b |
mov dword [eax+800h], 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 ecx, 4 |
mov edx, 0x9C000 |
push eax |
lea edi, [eax+0x9C*4] |
@@: |
lea eax, [edx + OS_BASE] |
mov [edi+800h], eax |
lea eax, [edx + 111b] |
stosd |
add edx, 0x1000 |
loop @b |
pop eax |
pop edi |
; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!) |
; physical address = 0xC0000 |
; linear address = 0x800C0000 |
mov ecx, 0xC0 |
@@: |
mov edx, ecx |
shl edx, 12 |
push edx |
or edx, 111b |
mov [eax+ecx*4], edx |
pop edx |
add edx, OS_BASE |
mov [eax+ecx*4+0x800], edx |
inc cl |
jnz @b |
mov eax, ebx |
ret |
.fail2: |
mov eax, ebx |
call free |
.fail: |
xor eax, eax |
ret |
; 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 |
mov edx, [esi+V86_machine.pages] |
shr ecx, 12 |
and eax, 0xFFF |
add eax, [edx+ecx*4] ; atomic operation, no mutex needed |
pop edx ecx |
ret |
; 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 byte [OS_BASE + 0x500], 0xCD |
mov byte [OS_BASE + 0x501], 0x13 |
mov byte [OS_BASE + 0x502], 0xF4 |
mov byte [OS_BASE + 0x503], 0xCD |
mov byte [OS_BASE + 0x504], 0x10 |
mov byte [OS_BASE + 0x505], 0xF4 |
mov esi, eax |
mov ebx, [eax+V86_machine.pagedir] |
; one page for stack, two pages for results (0x2000 bytes = 16 sectors) |
mov dword [ebx+0x99*4+0x1000], 0x99000 or 111b |
mov dword [ebx+0x99*4+0x1800], OS_BASE + 0x99000 |
mov dword [ebx+0x9A*4+0x1000], 0x9A000 or 111b |
mov dword [ebx+0x9A*4+0x1800], OS_BASE + 0x9A000 |
mov dword [ebx+0x9B*4+0x1000], 0x9B000 or 111b |
mov dword [ebx+0x9B*4+0x1800], OS_BASE + 0x9B000 |
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_TASK] |
shl ecx, 8 |
add ecx, SLOT_BASE |
mov eax, [esi+V86_machine.iopm] |
call get_pg_addr |
inc eax |
push dword [ecx+APPDATA.io_map] |
push dword [ecx+APPDATA.io_map+4] |
mov dword [ecx+APPDATA.io_map], eax |
mov dword [page_tabs + (tss._io_map_0 shr 10)], eax |
add eax, 0x1000 |
mov dword [ecx+APPDATA.io_map+4], eax |
mov dword [page_tabs + (tss._io_map_1 shr 10)], eax |
push [ecx+APPDATA.dir_table] |
push [ecx+APPDATA.saved_esp0] |
mov [ecx+APPDATA.saved_esp0], esp |
mov [tss._esp0], esp |
mov eax, [esi+V86_machine.pagedir] |
call get_pg_addr |
mov [ecx+APPDATA.dir_table], eax |
mov cr3, eax |
; mov [irq_tab+5*4], my05 |
; 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) |
; ᫨ ¡ë ¬ë ¬®£«¨ áå«®¯®â âì ¨áª«î票¥ ⮫쪮 ¨§-§ çâ¥¨ï ¡ ©â®¢ ª®¤ , |
; ¬ë ¡ë ¥£® 㦥 áå«®¯®â «¨ ¨ íâ® ¡ë«® ¡ë ¥ #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_TASK] |
shl ecx, 8 |
pop eax |
mov [SLOT_BASE+ecx+APPDATA.saved_esp0], eax |
mov [tss._esp0], eax |
pop eax |
mov [SLOT_BASE+ecx+APPDATA.dir_table], eax |
pop ebx |
mov dword [SLOT_BASE+ecx+APPDATA.io_map+4], ebx |
mov dword [page_tabs + (tss._io_map_1 shr 10)], ebx |
pop ebx |
mov dword [SLOT_BASE+ecx+APPDATA.io_map], ebx |
mov dword [page_tabs + (tss._io_map_0 shr 10)], ebx |
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.pagedir] |
call get_pg_addr |
mov ecx, [CURRENT_TASK] |
shl ecx, 8 |
cmp [SLOT_BASE+ecx+APPDATA.dir_table], 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, [TASK_COUNT] |
.scan: |
cmp [ebx+APPDATA.dir_table], 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 cr3, eax |
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_DATA |
call find_next_task.found |
call do_change_task |
popad |
iretd |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/apic.inc |
---|
0,0 → 1,443 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
iglobal |
IRQ_COUNT dd 24 |
endg |
uglobal |
irq_mode rd 1 |
IOAPIC_base rd 1 |
LAPIC_BASE rd 1 |
endg |
APIC_ID equ 0x20 |
APIC_TPR equ 0x80 |
APIC_EOI equ 0xb0 |
APIC_LDR equ 0xd0 |
APIC_DFR equ 0xe0 |
APIC_SVR equ 0xf0 |
APIC_ISR equ 0x100 |
APIC_ESR equ 0x280 |
APIC_ICRL equ 0x300 |
APIC_ICRH equ 0x310 |
APIC_LVT_LINT0 equ 0x350 |
APIC_LVT_LINT1 equ 0x360 |
APIC_LVT_err equ 0x370 |
; APIC timer |
APIC_LVT_timer equ 0x320 |
APIC_timer_div equ 0x3e0 |
APIC_timer_init equ 0x380 |
APIC_timer_cur equ 0x390 |
; IOAPIC |
IOAPIC_ID equ 0x0 |
IOAPIC_VER equ 0x1 |
IOAPIC_ARB equ 0x2 |
IOAPIC_REDTBL equ 0x10 |
align 4 |
APIC_init: |
mov [irq_mode], IRQ_PIC |
cmp [acpi_ioapic_base], 0 |
jz .no_apic |
cmp [acpi_lapic_base], 0 |
jz .no_apic |
stdcall load_file, dev_data_path |
test eax, eax |
jz .no_apic |
mov [acpi_dev_data], eax |
mov [acpi_dev_size], ebx |
call IRQ_mask_all |
; IOAPIC init |
stdcall map_io_mem, [acpi_ioapic_base], 0x20, PG_SW+PG_NOCACHE |
mov [IOAPIC_base], eax |
mov eax, IOAPIC_VER |
call IOAPIC_read |
shr eax, 16 |
inc al |
movzx eax, al |
cmp al, IRQ_RESERVED |
jbe @f |
mov al, IRQ_RESERVED |
@@: |
mov [IRQ_COUNT], eax |
; Reroute IOAPIC & mask all interrupts |
xor ecx, ecx |
mov eax, IOAPIC_REDTBL |
@@: |
mov ebx, eax |
call IOAPIC_read |
mov ah, 0x09; Delivery Mode: Lowest Priority, Destination Mode: Logical |
mov al, cl |
add al, 0x20; vector |
or eax, 0x10000; Mask Interrupt |
cmp ecx, 16 |
jb .set |
or eax, 0xa000;<<< level-triggered active-low for IRQ16+ |
.set: |
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] |
jb @b |
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: |
ret |
;=========================================================== |
align 4 |
LAPIC_init: |
cmp [LAPIC_BASE], 0 |
jne .done |
stdcall map_io_mem, [acpi_lapic_base], 0x1000, PG_SW+PG_NOCACHE |
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_base] |
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_base] |
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: |
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 |
; mov dword[irq_type_to_set], IRQ_TYPE_PIC |
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: |
mov ecx, [IRQ_COUNT] |
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 |
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: |
shl ebx, 1 |
add ebx, 0x10 |
mov eax, ebx |
call IOAPIC_read |
and eax, 0xfffeffff; bit 16 |
xchg eax, ebx |
call IOAPIC_write |
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: |
shl ebx, 1 |
add ebx, 0x10 |
mov eax, ebx |
call IOAPIC_read |
or eax, 0x10000; bit 16 |
xchg eax, ebx |
call IOAPIC_write |
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 |
/kernel/branches/net/core/conf_lib-sp.inc |
---|
0,0 → 1,11 |
; ste archivo debe ser editado con codificaci¢n CP866 |
ugui_mouse_speed db 'velocidad del rat¢n',0 |
ugui_mouse_delay db 'demora del rat¢n',0 |
udev db 'disp',0 |
unet db 'red',0 |
unet_active db 'activa',0 |
unet_addr db 'direc',0 |
unet_mask db 'm sc',0 |
unet_gate db 'puer',0 |
/kernel/branches/net/core/conf_lib.inc |
---|
0,0 → 1,221 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/dll.inc |
---|
0,0 → 1,1453 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
DRV_COMPAT equ 5 ;minimal required drivers version |
DRV_CURRENT equ 6 ;current drivers model version |
DRV_VERSION equ (DRV_COMPAT shl 16) or DRV_CURRENT |
PID_KERNEL equ 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 |
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 |
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 |
je .ok |
mov edx, [edx+SRV.fd] |
jmp @B |
.not_load: |
pop ebp |
jmp load_driver |
.ok: |
mov eax, edx |
ret |
endp |
align 4 |
proc reg_service stdcall, name:dword, handler:dword |
push ebx |
xor eax, eax |
cmp [name], eax |
je .fail |
cmp [handler], eax |
je .fail |
mov eax, sizeof.SRV |
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_TASK] |
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] |
int 0x40 |
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 |
; description |
; allocate kernel memory and loads the specified file |
; |
; param |
; file_name= full path to file |
; |
; retval |
; eax= file image in kernel 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 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], 0x4B43504B |
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 |
uglobal |
align 4 |
unpack_mutex MUTEX |
endg |
align 4 |
proc get_proc_ex stdcall, proc_name:dword, imports:dword |
.look_up: |
mov edx, [imports] |
test edx, edx |
jz .end |
mov edx, [edx] |
test edx, edx |
jz .end |
.next: |
mov eax, [edx] |
test eax, eax |
jz .next_table |
push edx |
stdcall strncmp, eax, [proc_name], 256 |
pop edx |
test eax, eax |
jz .ok |
add edx, 8 |
jmp .next |
.next_table: |
add [imports], 4 |
jmp .look_up |
.ok: |
mov eax, [edx+4] |
ret |
.end: |
xor eax, eax |
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 |
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 |
align 4 |
proc load_driver stdcall, driver_name:dword |
locals |
coff dd ? |
sym dd ? |
strings dd ? |
img_size dd ? |
img_base dd ? |
start dd ? |
exports dd ? ;fake exports table |
dd ? |
file_name rb 13+16+4+1 ; '/sys/drivers/<up-to-16-chars>.obj' |
endl |
lea edx, [file_name] |
mov dword [edx], '/sys' |
mov dword [edx+4], '/dri' |
mov dword [edx+8], 'vers' |
mov byte [edx+12], '/' |
mov esi, [driver_name] |
.redo: |
lea edx, [file_name] |
lea edi, [edx+13] |
mov ecx, 16 |
@@: |
lodsb |
test al, al |
jz @f |
stosb |
loop @b |
@@: |
mov dword [edi], '.obj' |
mov byte [edi+4], 0 |
stdcall load_file, edx |
test eax, eax |
jz .exit |
mov [coff], eax |
movzx ecx, [eax+COFF_HEADER.nSections] |
xor ebx, ebx |
lea edx, [eax+20] |
@@: |
add ebx, [edx+COFF_SECTION.SizeOfRawData] |
add ebx, 15 |
and ebx, not 15 |
add edx, sizeof.COFF_SECTION |
dec ecx |
jnz @B |
mov [img_size], ebx |
stdcall kernel_alloc, ebx |
test eax, eax |
jz .fail |
mov [img_base], eax |
mov edi, eax |
xor eax, eax |
mov ecx, [img_size] |
add ecx, 4095 |
and ecx, not 4095 |
shr ecx, 2 |
cld |
rep stosd |
mov edx, [coff] |
movzx ebx, [edx+COFF_HEADER.nSections] |
mov edi, [img_base] |
lea eax, [edx+20] |
@@: |
mov [eax+COFF_SECTION.VirtualAddress], edi |
mov esi, [eax+COFF_SECTION.PtrRawData] |
test esi, esi |
jnz .copy |
add edi, [eax+COFF_SECTION.SizeOfRawData] |
jmp .next |
.copy: |
add esi, edx |
mov ecx, [eax+COFF_SECTION.SizeOfRawData] |
cld |
rep movsb |
.next: |
add edi, 15 |
and edi, not 15 |
add eax, sizeof.COFF_SECTION |
dec ebx |
jnz @B |
mov ebx, [edx+COFF_HEADER.pSymTable] |
add ebx, edx |
mov [sym], ebx |
mov ecx, [edx+COFF_HEADER.nSymbols] |
add ecx, ecx |
lea ecx, [ecx+ecx*8];ecx*=18 = nSymbols*CSYM_SIZE |
add ecx, [sym] |
mov [strings], ecx |
lea ebx, [exports] |
mov dword [ebx], kernel_export |
mov dword [ebx+4], 0 |
lea eax, [edx+20] |
stdcall fix_coff_symbols, eax, [sym], [edx+COFF_HEADER.nSymbols], \ |
[strings], ebx |
test eax, eax |
jz .link_fail |
mov ebx, [coff] |
stdcall fix_coff_relocs, ebx, [sym], 0 |
stdcall get_coff_sym, [sym], [ebx+COFF_HEADER.nSymbols], szVersion |
test eax, eax |
jz .link_fail |
mov eax, [eax] |
shr eax, 16 |
cmp eax, DRV_COMPAT |
jb .ver_fail |
cmp eax, DRV_CURRENT |
ja .ver_fail |
mov ebx, [coff] |
stdcall get_coff_sym, [sym], [ebx+COFF_HEADER.nSymbols], szSTART |
mov [start], eax |
stdcall kernel_free, [coff] |
mov ebx, [start] |
stdcall ebx, DRV_ENTRY |
test eax, eax |
jnz .ok |
stdcall kernel_free, [img_base] |
xor eax, eax |
ret |
.ok: |
mov ebx, [img_base] |
mov [eax+SRV.base], ebx |
mov ecx, [start] |
mov [eax+SRV.entry], ecx |
ret |
.ver_fail: |
mov esi, msg_CR |
call sys_msg_board_str |
mov esi, [driver_name] |
call sys_msg_board_str |
mov esi, msg_CR |
call sys_msg_board_str |
mov esi, msg_version |
call sys_msg_board_str |
mov esi, msg_www |
call sys_msg_board_str |
jmp .cleanup |
.link_fail: |
mov esi, msg_module |
call sys_msg_board_str |
mov esi, [driver_name] |
call sys_msg_board_str |
mov esi, msg_CR |
call sys_msg_board_str |
.cleanup: |
stdcall kernel_free, [img_base] |
.fail: |
stdcall kernel_free, [coff] |
.exit: |
xor eax, eax |
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 |
locals |
fullname rb 260 |
fileinfo rb 40 |
coff dd ? |
img_base dd ? |
endl |
cli |
; resolve file name |
mov ebx, [file_name] |
lea edi, [fullname+1] |
mov byte [edi-1], '/' |
stdcall get_full_file_name, edi, 259 |
test al, al |
jz .fail |
; scan for required DLL in list of already loaded for this process, |
; ignore timestamp |
mov esi, [CURRENT_TASK] |
shl esi, 8 |
lea edi, [fullname] |
mov ebx, [esi+SLOT_BASE+APPDATA.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] |
ret |
.next_in_process: |
mov esi, [esi+HDLL.fd] |
jmp .scan_in_process |
.not_in_process: |
; scan in full list, compare timestamp |
lea eax, [fileinfo] |
stdcall get_fileinfo, edi, eax |
test eax, eax |
jnz .fail |
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: |
; 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 |
; 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 |
; 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] |
.dll_already_loaded: |
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_TASK] |
shl ebx, 5 |
mov edx, [CURRENT_TASK+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], DONT_FREE_BLOCK |
; 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_USER |
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] |
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: |
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 |
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_slot] |
mov eax, [ebx+APPDATA.dlls_list_ptr] |
test eax, eax |
jnz .ret |
push [ebx+APPDATA.dir_table] |
mov eax, 8 |
call malloc |
pop edx |
test eax, eax |
jz .ret |
mov [eax], eax |
mov [eax+4], eax |
mov ecx, [TASK_COUNT] |
mov ebx, SLOT_BASE+256 |
.set: |
cmp [ebx+APPDATA.dir_table], edx |
jnz @f |
mov [ebx+APPDATA.dlls_list_ptr], eax |
@@: |
add ebx, 256 |
dec ecx |
jnz .set |
.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 |
push eax |
mov ebx, [eax+HDLL.base] |
mov esi, [eax+HDLL.parent] |
mov edx, [esi+DLLDESCR.size] |
; The following actions require the context of application where HDLL is mapped. |
; However, destroy_hdll can be called in the context of OS thread when |
; cleaning up objects created by the application which is destroyed. |
; So remember current cr3 and set it to page table of target. |
mov eax, [ecx+APPDATA.dir_table] |
; Because we cheat with cr3, disable interrupts: task switch would restore |
; page table from APPDATA of current thread. |
; Also set [current_slot] because it is used by user_free. |
pushf |
cli |
push [current_slot] |
mov [current_slot], ecx |
mov ecx, cr3 |
push ecx |
mov cr3, eax |
push ebx ; argument for user_free |
mov eax, ebx |
shr ebx, 12 |
push ebx |
mov esi, [esi+DLLDESCR.data] |
shr esi, 12 |
.unmap_loop: |
push eax |
mov eax, 2 |
xchg eax, [page_tabs+ebx*4] |
mov ecx, [page_tabs+esi*4] |
and eax, not 0xFFF |
and ecx, not 0xFFF |
cmp eax, ecx |
jz @f |
call free_page |
@@: |
pop eax |
invlpg [eax] |
add eax, 0x1000 |
inc ebx |
inc esi |
sub edx, 0x1000 |
ja .unmap_loop |
pop ebx |
and dword [page_tabs+(ebx-1)*4], not DONT_FREE_BLOCK |
call user_free |
; Restore context. |
pop eax |
mov cr3, eax |
pop [current_slot] |
popf |
; Ok, cheating is done. |
pop eax |
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 |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/irq.inc |
---|
0,0 → 1,229 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
IRQ_RESERVED equ 24 |
IRQ_POOL_SIZE equ 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 1 |
irq_failed rd IRQ_RESERVED |
endg |
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 |
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 |
pushfd |
cli |
;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 |
lea edx, [irqh_tab+ebx*8] |
list_add_tail ecx, edx ;clobber eax |
stdcall enable_irq, ebx |
.fail: |
popfd |
.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: |
; .irq_1: |
; push 1 |
; jmp .main |
; etc... |
irq_serv_h 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15 |
irq_serv_h 16, 17, 18, 19, 20, 21, 22, 23 |
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 |
cmp bp, 6 |
jnz @f |
push ebp |
call [fdc_irq_func] |
pop ebp |
@@: |
cmp bp, 14 |
jnz @f |
push ebp |
call [irq14_func] |
pop ebp |
@@: |
cmp bp, 15 |
jnz @f |
push ebp |
call [irq15_func] |
pop ebp |
@@: |
bts [irq_active_set], ebp |
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] |
add esp, 4 |
pop esi |
pop edi |
pop ebx |
test eax, eax |
jz .next |
btr [irq_active_set], ebp |
jmp .next |
.done: |
btr [irq_active_set], ebp |
jnc .exit |
inc [irq_failed+ebp*4] |
.exit: |
mov [check_idle_semaphore], 5 |
mov ecx, ebp |
call irq_eoi |
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 |
/kernel/branches/net/core/malloc.inc |
---|
0,0 → 1,1035 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 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 |
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 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 |
.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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/memory.inc |
---|
0,0 → 1,1582 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 |
push ebx |
mov eax, [phis_addr] |
and eax, not 0xFFF |
or eax, [flags] |
mov ebx, [lin_addr] |
shr ebx, 12 |
mov [page_tabs+ebx*4], eax |
mov eax, [lin_addr] |
invlpg [eax] |
pop ebx |
ret |
endp |
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 |
and edx, -4096 |
or edx, [flags] |
@@: |
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 |
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_UW ;+PG_NOCACHE |
mov dword [master_tab+ebx*4], eax |
mov eax, [lin_addr] |
shr eax, 10 |
add eax, page_tabs |
invlpg [eax] |
pop ebx |
ret |
endp |
align 4 |
proc init_LFB |
locals |
pg_count dd ? |
endl |
cmp dword [LFBAddress], -1 |
jne @f |
mov [BOOT_VAR+BOOT_MTRR], byte 2 |
; max VGA=640*480*4=1228800 bytes |
; + 32*640*4=81920 bytes for mouse pointer |
stdcall alloc_pages, ((1228800+81920)/4096) |
push eax |
call alloc_page |
stdcall map_page_table, LFB_BASE, eax |
pop eax |
or eax, PG_UW |
mov ebx, LFB_BASE |
; max VGA=640*480*4=1228800 bytes |
; + 32*640*4=81920 bytes for mouse pointer |
mov ecx, (1228800+81920)/4096 |
call commit_pages |
mov [LFBAddress], dword LFB_BASE |
ret |
@@: |
test [SCR_MODE], word 0100000000000000b |
jnz @f |
mov [BOOT_VAR+BOOT_MTRR], byte 2 |
ret |
@@: |
call init_mtrr |
mov edx, LFB_BASE |
mov esi, [LFBAddress] |
mov edi, 0x00C00000 |
mov dword [exp_lfb+4], edx |
shr edi, 12 |
mov [pg_count], edi |
shr edi, 10 |
bt [cpu_caps], CAPS_PSE |
jnc .map_page_tables |
or esi, PG_LARGE+PG_UW |
mov edx, sys_pgdir+(LFB_BASE shr 20) |
@@: |
mov [edx], esi |
add edx, 4 |
add esi, 0x00400000 |
dec edi |
jnz @B |
bt [cpu_caps], CAPS_PGE |
jnc @F |
or dword [sys_pgdir+(LFB_BASE shr 20)], PG_GLOBAL |
@@: |
mov dword [LFBAddress], LFB_BASE |
mov eax, cr3 ;flush TLB |
mov cr3, eax |
ret |
.map_page_tables: |
@@: |
call alloc_page |
stdcall map_page_table, edx, eax |
add edx, 0x00400000 |
dec edi |
jnz @B |
mov eax, [LFBAddress] |
mov edi, page_tabs + (LFB_BASE shr 10) |
or eax, PG_UW |
mov ecx, [pg_count] |
cld |
@@: |
stosd |
add eax, 0x1000 |
dec ecx |
jnz @B |
mov dword [LFBAddress], LFB_BASE |
mov eax, cr3 ;flush TLB |
mov cr3, eax |
ret |
endp |
align 4 |
proc new_mem_resize stdcall, new_size:dword |
push ebx |
push esi |
push edi |
mov edx, [current_slot] |
cmp [edx+APPDATA.heap_base], 0 |
jne .exit |
mov edi, [new_size] |
add edi, 4095 |
and edi, not 4095 |
mov [new_size], edi |
mov esi, [edx+APPDATA.mem_size] |
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] |
call update_mem_size |
.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 |
align 4 |
update_mem_size: |
; in: edx = slot base |
; ebx = new memory size |
; destroys eax,ecx,edx |
mov [APPDATA.mem_size+edx], ebx |
;search threads and update |
;application memory size infomation |
mov ecx, [APPDATA.dir_table+edx] |
mov eax, 2 |
.search_threads: |
;eax = current slot |
;ebx = new memory size |
;ecx = page directory |
cmp eax, [TASK_COUNT] |
jg .search_threads_end |
mov edx, eax |
shl edx, 5 |
cmp word [CURRENT_TASK+edx+TASKDATA.state], 9 ;if slot empty? |
jz .search_threads_next |
shl edx, 3 |
cmp [SLOT_BASE+edx+APPDATA.dir_table], ecx ;if it is our thread? |
jnz .search_threads_next |
mov [SLOT_BASE+edx+APPDATA.mem_size], ebx ;update memory size |
.search_threads_next: |
inc eax |
jmp .search_threads |
.search_threads_end: |
ret |
; param |
; eax= linear address |
; |
; retval |
; eax= phisical 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 ;ñòðàíèöà â ïàìÿòè ïðèëîæåíèÿ ; |
cmp ebx, page_tabs |
jb .kernel_space ;ñòðàíèöà â ïàìÿòè ÿäðà |
cmp ebx, kernel_tabs |
jb .alloc;.app_tabs ;òàáëèöû ñòðàíèö ïðèëîæåíèÿ ; |
;ïðîñòî ñîçäàäèì îäíó |
if 0 ;ïîêà ýòî ïðîñòî ëèøíåå |
cmp ebx, LFB_BASE |
jb .core_tabs ;òàáëèöû ñòðàíèö ÿäðà |
;Îøèáêà |
.lfb: |
;îáëàñòü LFB |
;Îøèáêà |
jmp .fail |
end if |
.core_tabs: |
.fail: ;simply return to caller |
mov esp, ebp |
pop ebx ;restore exception number (#PF) |
ret |
; xchg bx, bx |
; add esp,12 ;clear in stack: locals(.err_addr) + #PF + ret_to_caller |
; restore_ring3_context |
; iretd |
.user_space: |
test eax, PG_MAP |
jnz .err_access ;Ñòðàíèöà ïðèñóòñòâóåò |
;Îøèáêà äîñòóïà ? |
shr ebx, 12 |
mov ecx, ebx |
shr ecx, 10 |
mov edx, [master_tab+ecx*4] |
test edx, PG_MAP |
jz .fail ;òàáëèöà ñòðàíèö íå ñîçäàíà |
;íåâåðíûé àäðåñ â ïðîãðàììå |
mov eax, [page_tabs+ebx*4] |
test eax, 2 |
jz .fail ;àäðåñ íå çàðåçåðâèðîâàí äëÿ ; |
;èñïîëüçîâàíèÿ. Îøèáêà |
.alloc: |
call alloc_page |
test eax, eax |
jz .fail |
stdcall map_page, [.err_addr], eax, PG_UW |
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_TASK] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.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_UW |
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_MAP |
jz .fail ;ñòðàíèöà íå ïðèñóòñòâóåò |
test eax, 12 ;U/S (+below) |
jnz .fail ;ïðèëîæåíèå îáðàòèëîñü ê ïàìÿòè |
;ÿäðà |
;test eax, 8 |
;jnz .fail ;óñòàíîâëåí çàðåçåðâèðîâàííûé áèò |
;â òàáëèöàõ ñòðàíèö. äîáàâëåíî â P4/Xeon |
;ïîïûòêà çàïèñè â çàùèù¸ííóþ ñòðàíèöó ÿäðà |
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_SW |
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_SW |
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 stdcall, lin_addr:dword,slot:dword,\ |
ofs:dword,buf_size:dword,req_access:dword |
push 0 ; initialize number of mapped bytes |
cmp [buf_size], 0 |
jz .exit |
mov eax, [slot] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.dir_table] |
and eax, 0xFFFFF000 |
stdcall map_page, [ipc_pdir], eax, PG_UW |
mov ebx, [ofs] |
shr ebx, 22 |
mov esi, [ipc_pdir] |
mov edi, [ipc_ptab] |
mov eax, [esi+ebx*4] |
and eax, 0xFFFFF000 |
jz .exit |
stdcall map_page, edi, eax, PG_UW |
; inc ebx |
; add edi, 0x1000 |
; mov eax, [esi+ebx*4] |
; test eax, eax |
; jz @f |
; and eax, 0xFFFFF000 |
; stdcall map_page, edi, eax |
@@: |
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 |
mov esi, [ipc_ptab] |
.map: |
stdcall safe_map_page, [slot], [req_access], [ofs] |
jnc .exit |
add dword [ebp-4], 4096 |
add [ofs], 4096 |
dec ecx |
jz .exit |
add edi, 0x1000 |
inc edx |
cmp edx, 0x400 |
jnz .map |
inc ebx |
mov eax, [ipc_pdir] |
mov eax, [eax+ebx*4] |
and eax, 0xFFFFF000 |
jz .exit |
stdcall map_page, esi, eax, PG_UW |
xor edx, edx |
jmp .map |
.exit: |
pop eax |
ret |
endp |
proc map_memEx stdcall, lin_addr:dword,slot:dword,\ |
ofs:dword,buf_size:dword,req_access:dword |
push 0 ; initialize number of mapped bytes |
cmp [buf_size], 0 |
jz .exit |
mov eax, [slot] |
shl eax, 8 |
mov eax, [SLOT_BASE+eax+APPDATA.dir_table] |
and eax, 0xFFFFF000 |
stdcall map_page, [proc_mem_pdir], eax, PG_UW |
mov ebx, [ofs] |
shr ebx, 22 |
mov esi, [proc_mem_pdir] |
mov edi, [proc_mem_tab] |
mov eax, [esi+ebx*4] |
and eax, 0xFFFFF000 |
test eax, eax |
jz .exit |
stdcall map_page, edi, eax, PG_UW |
@@: |
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 |
mov esi, [proc_mem_tab] |
.map: |
stdcall safe_map_page, [slot], [req_access], [ofs] |
jnc .exit |
add dword [ebp-4], 0x1000 |
add edi, 0x1000 |
add [ofs], 0x1000 |
inc edx |
dec ecx |
jnz .map |
.exit: |
pop eax |
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_MAP |
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_UW |
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.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_UW |
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 |
;align 4 |
;proc set_ipc_buff |
; mov eax,[current_slot] |
; pushf |
; cli |
; mov [eax+APPDATA.ipc_start],ebx ;set fields in extended information area |
; mov [eax+APPDATA.ipc_size],ecx |
; |
; add ecx, ebx |
; add ecx, 4095 |
; and ecx, not 4095 |
; |
;.touch: mov eax, [ebx] |
; add ebx, 0x1000 |
; cmp ebx, ecx |
; jb .touch |
; |
; popf |
; xor eax, eax |
; ret |
;endp |
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+0xa0] ;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+0xa4] |
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, ecx, [dst_slot], \ |
edi, esi, PG_SW |
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+0x04] ;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, 8 |
or [eax+SLOT_BASE+0xA8], dword 0x40 |
cmp dword [check_idle_semaphore], 20 |
jge .ipc_no_cis |
mov dword [check_idle_semaphore], 5 |
.ipc_no_cis: |
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] |
jz @f |
stdcall free_kernel_space, eax |
@@: |
pop eax |
popf |
ret |
endp |
align 4 |
sysfn_meminfo: |
; add ecx, new_app_base |
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 .fail |
cmp ebx, 25 |
ja .fail |
jmp dword [f68call+ebx*4-11*4] |
.11: |
call init_heap |
mov [esp+32], eax |
ret |
.12: |
stdcall user_alloc, ecx |
mov [esp+32], eax |
ret |
.13: |
stdcall user_free, ecx |
mov [esp+32], eax |
ret |
.14: |
cmp ecx, OS_BASE |
jae .fail |
mov edi, ecx |
call get_event_ex |
mov [esp+32], eax |
ret |
.16: |
test ecx, ecx |
jz .fail |
cmp ecx, OS_BASE |
jae .fail |
stdcall get_service, ecx |
mov [esp+32], eax |
ret |
.17: |
call srv_handlerEx ;ecx |
mov [esp+32], eax |
ret |
.19: |
cmp ecx, OS_BASE |
jae .fail |
stdcall load_library, ecx |
mov [esp+32], eax |
ret |
.20: |
mov eax, edx |
mov ebx, ecx |
call user_realloc ;in: eax = pointer, ebx = new size |
mov [esp+32], eax |
ret |
.21: |
cmp ecx, OS_BASE |
jae .fail |
cmp edx, OS_BASE |
jae .fail |
mov edi, edx |
stdcall load_PE, ecx |
mov esi, eax |
test eax, eax |
jz @F |
push edi |
push DRV_ENTRY |
call eax |
add esp, 8 |
test eax, eax |
jz @F |
mov [eax+SRV.entry], esi |
@@: |
mov [esp+32], eax |
ret |
.22: |
cmp ecx, OS_BASE |
jae .fail |
stdcall shmem_open, ecx, edx, esi |
mov [esp+24], edx |
mov [esp+32], eax |
ret |
.23: |
cmp ecx, OS_BASE |
jae .fail |
stdcall shmem_close, ecx |
mov [esp+32], eax |
ret |
.24: |
mov eax, [current_slot] |
xchg ecx, [eax+APPDATA.exc_handler] |
xchg edx, [eax+APPDATA.except_mask] |
mov [esp+32], ecx ; reg_eax+8 |
mov [esp+20], edx ; reg_ebx+8 |
ret |
.25: |
cmp ecx, 32 |
jae .fail |
mov eax, [current_slot] |
btr [eax+APPDATA.except_mask], ecx |
setc byte[esp+32] |
jecxz @f |
bts [eax+APPDATA.except_mask], ecx |
@@: |
ret |
.26: |
stdcall user_unmap, ecx, edx, esi |
mov [esp+32], eax |
ret |
.fail: |
xor eax, eax |
mov [esp+32], 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.fail ; moved to f68.25 |
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 |
align 4 |
proc load_pe_driver stdcall, file:dword |
stdcall load_PE, [file] |
test eax, eax |
jz .fail |
mov esi, eax |
stdcall eax, DRV_ENTRY |
test eax, eax |
jz .fail |
mov [eax+SRV.entry], esi |
ret |
.fail: |
xor eax, eax |
ret |
endp |
align 4 |
proc init_mtrr |
cmp [BOOT_VAR+BOOT_MTRR], byte 2 |
je .exit |
bt [cpu_caps], CAPS_MTRR |
jnc .exit |
mov eax, cr0 |
or eax, 0x60000000 ;disable caching |
mov cr0, eax |
wbinvd ;invalidate cache |
mov ecx, 0x2FF |
rdmsr ; |
; has BIOS already initialized MTRRs? |
test ah, 8 |
jnz .skip_init |
; rarely needed, so mainly placeholder |
; main memory - cached |
push eax |
mov eax, [MEM_AMOUNT] |
; round eax up to next power of 2 |
dec eax |
bsr ecx, eax |
mov ebx, 2 |
shl ebx, cl |
dec ebx |
; base of memory range = 0, type of memory range = MEM_WB |
xor edx, edx |
mov eax, MEM_WB |
mov ecx, 0x200 |
wrmsr |
; mask of memory range = 0xFFFFFFFFF - (size - 1), ebx = size - 1 |
mov eax, 0xFFFFFFFF |
mov edx, 0x0000000F |
sub eax, ebx |
sbb edx, 0 |
or eax, 0x800 |
inc ecx |
wrmsr |
; clear unused MTRRs |
xor eax, eax |
xor edx, edx |
@@: |
wrmsr |
inc ecx |
cmp ecx, 0x210 |
jb @b |
; enable MTRRs |
pop eax |
or ah, 8 |
and al, 0xF0; default memtype = UC |
mov ecx, 0x2FF |
wrmsr |
.skip_init: |
stdcall set_mtrr, [LFBAddress], [LFBSize], MEM_WC |
wbinvd ;again invalidate |
mov eax, cr0 |
and eax, not 0x60000000 |
mov cr0, eax ; enable caching |
.exit: |
ret |
endp |
align 4 |
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword |
; find unused register |
mov ecx, 0x201 |
@@: |
rdmsr |
dec ecx |
test ah, 8 |
jz .found |
rdmsr |
mov al, 0; clear memory type field |
cmp eax, [base] |
jz .ret |
add ecx, 3 |
cmp ecx, 0x210 |
jb @b |
; no free registers, ignore the call |
.ret: |
ret |
.found: |
; found, write values |
xor edx, edx |
mov eax, [base] |
or eax, [mem_type] |
wrmsr |
mov ebx, [size] |
dec ebx |
mov eax, 0xFFFFFFFF |
mov edx, 0x00000000 |
sub eax, ebx |
sbb edx, 0 |
or eax, 0x800 |
inc ecx |
wrmsr |
ret |
endp |
align 4 |
proc stall stdcall, delay:dword |
push ecx |
push edx |
push ebx |
push eax |
mov eax, [delay] |
mul [stall_mcs] |
mov ebx, eax ;low |
mov ecx, edx ;high |
rdtsc |
add ebx, eax |
adc ecx, edx |
@@: |
rdtsc |
sub eax, ebx |
sbb edx, ecx |
jb @B |
pop eax |
pop ebx |
pop edx |
pop ecx |
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_VAR + 0x9104 |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/sys32-sp.inc |
---|
0,0 → 1,4 |
; ste archivo debe ser editado con codificaci¢n CP866 |
msg_sel_ker db "n£cleo", 0 |
msg_sel_app db "aplicaci¢n", 0 |
/kernel/branches/net/core/sys32.inc |
---|
0,0 → 1,798 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; MenuetOS process management, protected ring3 ;; |
;; ;; |
;; Distributed under GPL. See file COPYING for details. ;; |
;; Copyright 2003 Ville Turjanmaa ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$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 |
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 .. 0x2F - IRQ handlers |
dd irq0, irq_serv.irq_1, irq_serv.irq_2 |
dd irq_serv.irq_3, irq_serv.irq_4 |
dd irq_serv.irq_5, irq_serv.irq_6, irq_serv.irq_7 |
dd irq_serv.irq_8, irq_serv.irq_9, irq_serv.irq_10 |
dd irq_serv.irq_11, irq_serv.irq_12, irqD, irq_serv.irq_14, irq_serv.irq_15 |
dd irq_serv.irq_16 |
dd irq_serv.irq_17 |
dd irq_serv.irq_18 |
dd irq_serv.irq_19 |
dd irq_serv.irq_20 |
dd irq_serv.irq_21 |
dd irq_serv.irq_22 |
dd irq_serv.irq_23 |
times 32 - IRQ_RESERVED dd unknown_interrupt |
;int_0x40 gate trap (for directly copied) |
dw i40 and 0xFFFF, os_code, 11101111b shl 8, i40 shr 16 |
idtreg: ; data for LIDT instruction (!!! must be immediately below sys_int data) |
dw 2*($-sys_int-4)-1 |
dd idts ;0x8000B100 |
dw 0 ;ïðîñòî âûðàâíèâàíèå |
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_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 |
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: ; äóðàêîóñòî÷èâîñòü: ñåëåêòîðû èñïîð÷åíû... |
pop [ss:pf_err_code]; äåéñòâèòåëüíî äî ñëåäóþùåãî #PF |
save_ring3_context |
mov bl, 14 |
exc_c: ; èñêëþ÷åíèÿ (âñå, êðîìå 7-ãî - #NM) |
; Ôðýéì ñòåêà ïðè èñêëþ÷åíèè/ïðåðûâàíèè èç 3-ãî êîëüöà + pushad (ò.å., èìåííî çäåñü) |
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 |
; ýòî ôðýéì îò 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 ;èñêëþ÷åíèå |
mov ds, ax ;çàãðóçèì ïðàâèëüíûå çíà÷åíèÿ |
mov es, ax ;â ðåãèñòðû |
cld ; è ïðèâîäèì DF ê ñòàíäàðòó |
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 |
sti |
; not debuggee => say error and terminate |
call show_error_parameters ;; only ONE using, inline ??? |
; kill open sockets |
pusha |
mov edx, [edx + TASKDATA.pid] |
call SOCKET_process_end |
popa |
mov [edx + TASKDATA.state], byte 4 ; terminate |
jmp change_task ; stack - here it does not matter at all, SEE: core/shed.inc |
.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 byte [edx+TASKDATA.state], 1 ; 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, 0x0e |
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 |
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 |
set_application_table_status: |
push eax |
mov eax, [CURRENT_TASK] |
shl eax, 5 |
add eax, CURRENT_TASK+TASKDATA.pid |
mov eax, [eax] |
mov [application_table_status], eax |
pop eax |
ret |
align 4 |
clear_application_table_status: |
push eax |
mov eax, [CURRENT_TASK] |
shl eax, 5 |
add eax, CURRENT_TASK+TASKDATA.pid |
mov eax, [eax] |
cmp eax, [application_table_status] |
jne apptsl1 |
xor eax, eax |
mov [application_table_status], eax |
apptsl1: |
pop eax |
ret |
; * eax = 64 - íîìåð ôóíêöèè |
; * ebx = 1 - åäèíñòâåííàÿ ïîäôóíêöèÿ |
; * ecx = íîâûé ðàçìåð ïàìÿòè |
;Âîçâðàùàåìîå çíà÷åíèå: |
; * eax = 0 - óñïåøíî |
; * eax = 1 - íåäîñòàòî÷íî ïàìÿòè |
align 4 |
sys_resize_app_memory: |
; ebx = 1 - resize |
; ecx = new amount of memory |
; cmp eax,1 |
dec ebx |
jnz .no_application_mem_resize |
stdcall new_mem_resize, ecx |
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 |
.slot equ esp ;locals |
push esi ;save .slot |
shl esi, 8 |
cmp [SLOT_BASE+esi+APPDATA.dir_table], 0 |
jne @F |
pop esi |
shl esi, 5 |
mov [CURRENT_TASK+esi+TASKDATA.state], 9 |
ret |
@@: |
;mov esi,process_terminating |
;call sys_msg_board_str |
@@: |
cli |
cmp [application_table_status], 0 |
je term9 |
sti |
call change_task |
jmp @b |
term9: |
call set_application_table_status |
; 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.dir_table], 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: |
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 eax, [.slot] |
shl eax, 8 |
stdcall destroy_app_space, [SLOT_BASE+eax+APPDATA.dir_table], [SLOT_BASE+eax+APPDATA.dlls_list_ptr] |
mov esi, [.slot] |
cmp [fpu_owner], esi ; if user fpu last -> fpu user = 1 |
jne @F |
mov [fpu_owner], 1 |
mov eax, [256+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, 5 |
mov eax, [eax+CURRENT_TASK+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, 5 |
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 [esi+WDATA.box.left], eax |
mov [esi+WDATA.box.width], eax |
mov [esi+WDATA.box.top], eax |
mov [esi+WDATA.box.height], eax |
mov [esi+WDATA.cl_workarea], eax |
mov [esi+WDATA.cl_titlebar], eax |
mov [esi+WDATA.cl_frames], eax |
mov dword [esi+WDATA.reserved], eax; clear all flags: wstate, redraw, wdrawn |
lea edi, [esi-window_data+draw_data] |
mov ecx, 32/4 |
rep stosd |
popa |
; debuggee test |
pushad |
mov edi, esi |
shl edi, 5 |
mov eax, [SLOT_BASE+edi*8+APPDATA.debugger_slot] |
test eax, eax |
jz .nodebug |
push 8 |
pop ecx |
push dword [CURRENT_TASK+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+256+APPDATA.io_map] |
je @F |
call free_page |
@@: |
mov eax, [edi+APPDATA.io_map+4] |
cmp eax, [SLOT_BASE+256+APPDATA.io_map+4] |
je @F |
call free_page |
@@: |
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, [TASK_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, 5 |
cmp [CURRENT_TASK + edi + TASKDATA.state], byte 9 ; skip dead 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, 5 |
mov esi, [esi+CURRENT_TASK+TASKDATA.pid] |
cmp [hd1_status], esi |
jnz @f |
call free_hd_channel |
and [hd1_status], 0 |
@@: |
cmp [cd_status], esi |
jnz @f |
call free_cd_channel |
and [cd_status], 0 |
@@: |
cmp [flp_status], esi |
jnz @f |
and [flp_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, 5 |
add edx, CURRENT_TASK |
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, 5 |
mov [edi+CURRENT_TASK + TASKDATA.state], byte 9 |
; debugger test - terminate all debuggees |
mov eax, 2 |
mov ecx, SLOT_BASE+2*0x100+APPDATA.debugger_slot |
.xd0: |
cmp eax, [TASK_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: |
; call systest |
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 |
mov [MOUSE_BACKGROUND], byte 0; no mouse background |
mov [DONT_DRAW_MOUSE], byte 0; draw mouse |
and [application_table_status], 0 |
;mov esi,process_terminated |
;call sys_msg_board_str |
add esp, 4 |
ret |
restore .slot |
;iglobal |
;if lang eq ru |
; boot_sched_1 db '®§¤ ¨¥ GDT TSS 㪠§ ⥫ï',0 |
; boot_sched_2 db '®§¤ ¨¥ IDT â ¡«¨æë',0 |
;else |
; boot_sched_1 db 'Building gdt tss pointer',0 |
; boot_sched_2 db 'Building IDT table',0 |
;end if |
;endg |
;build_scheduler: |
; mov esi, boot_sched_1 |
; call boot_log |
; call build_process_gdt_tss_pointer |
; mov esi,boot_sched_2 |
; call boot_log |
; ret |
; 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*256. |
; 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/syscall.inc |
---|
0,0 → 1,213 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
; Old style system call converter |
align 16 |
cross_order: |
; load all registers in crossed order |
mov eax, ebx |
mov ebx, ecx |
mov ecx, edx |
mov edx, esi |
mov esi, edi |
movzx edi, byte[esp+28 + 4] |
sub edi, 53 |
call dword [servetable+edi*4] |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; SYSENTER ENTRY ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 32 |
sysenter_entry: |
; Íàñòðàèâàåì ñòåê |
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] ; â âåðøèí ñòåêà - 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 |
servetable: |
dd 0 |
dd 0 |
dd 0 |
dd 0 |
dd 0 |
dd file_system ; 58-Common file system interface |
dd 0 |
dd 0 |
dd 0 |
dd 0 ; 62-PCI functions |
dd sys_msg_board ; 63-System message board |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; NEW 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 syscall_openramdiskfile ; 6-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 old network stack |
dd undefined_syscall ; 53 old network stack |
dd undefined_syscall ; 54-reserved |
dd sound_interface ; 55-Sound interface |
dd undefined_syscall ; 56-reserved |
dd sys_pcibios ; 57-PCI BIOS32 |
dd cross_order ; 58-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 ;cross_order ; 62-PCI functions |
dd cross_order ; 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-Network stack |
dd sys_socket ; 75-Sockets |
dd sys_protocols ; 76-Protocols |
times 255 - ( ($-servetable2) /4 ) dd undefined_syscall |
dd sys_end ; -1-end application |
endg |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/taskman.inc |
---|
0,0 → 1,1245 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
GREEDY_KERNEL equ 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 |
hdrVersion1 = 1 ; it is the old version of the header, without console fields |
hdrVersionConsole = 2 ; it is the new version of the header, containing 2 mode dword fields |
struct APP_HEADER_02_ |
banner dq ? ; 'MENUET01' |
version dd ? ;+8 ; == hdrVersionConsole |
start dd ? ;+12 |
i_end dd ? ;+16 |
mem_size dd ? ;+20 |
stack_top dd ? ;+24 |
i_param dd ? ;+28 |
i_icon dd ? ;+32 |
stdio dd ? |
stderr dd ? |
ends |
struct APP_PARAMS |
app_cmdline dd ? ;0x00 |
app_path dd ? ;0x04 |
app_eip dd ? ;0x08 |
app_esp dd ? ;0x0C |
app_mem dd ? ;0x10 |
ends |
; not needed |
;macro _clear_ op |
;{ mov ecx, op/4 |
; xor eax, eax |
; cld |
; rep stosd |
;} |
fs_execute_from_sysdir: |
xor ebx, ebx ; command line arguments. |
fs_execute_from_sysdir_param: |
xor eax, eax ; no STDIO |
xor ecx, ecx ; no STDERR |
xor edx, edx ; flags (currently only debug flag). |
mov esi, sysdir_path |
align 4 |
proc fs_execute |
; eax - STDIO handle |
; ecx - STDERR handle |
; ebx - cmdline |
; edx - flags |
; ebp - full filename |
locals |
cmdline rd 64 ;256/4 |
filename rd 256 ;1024/4 |
flags dd ? |
save_cr3 dd ? |
slot dd ? |
slot_base dd ? |
file_base dd ? |
file_size dd ? |
handle dd ? ;temp. for default cursor handle for curr. thread |
;app header data |
hdr_cmdline dd ? ;0x00 |
hdr_path dd ? ;0x04 |
hdr_eip dd ? ;0x08 |
hdr_esp dd ? ;0x0C |
hdr_mem dd ? ;0x10 |
hdr_i_end dd ? ;0x14 |
hdr_stdio dd ? |
hdr_stderr dd ? |
endl |
pushad |
mov [hdr_stdio], eax |
mov [hdr_stderr], ecx |
cmp [SCR_MODE], word 0x13 |
jbe @f |
pushad |
stdcall set_cursor, [def_cursor_clock] |
mov [handle], eax |
mov [redrawmouse_unconditional], 1 |
call __sys_draw_pointer |
popad |
@@: |
mov [flags], edx |
; [ebp] pointer to filename |
lea edi, [filename] |
lea ecx, [edi+1024] |
mov al, '/' |
stosb |
@@: |
cmp edi, ecx |
jae .bigfilename |
lodsb |
stosb |
test al, al |
jnz @b |
mov esi, [ebp] |
test esi, esi |
jz .namecopied |
mov byte [edi-1], '/' |
@@: |
cmp edi, ecx |
jae .bigfilename |
lodsb |
stosb |
test al, al |
jnz @b |
jmp .namecopied |
.bigfilename: |
popad |
mov eax, -ERROR_FILE_NOT_FOUND |
jmp .final |
.namecopied: |
mov [cmdline], ebx |
test ebx, ebx |
jz @F |
lea eax, [cmdline] |
mov dword [eax+252], 0 |
stdcall strncpy, eax, ebx, 255 |
@@: |
lea eax, [filename] |
stdcall load_file, eax |
mov esi, -ERROR_FILE_NOT_FOUND |
test eax, eax |
jz .err_file |
mov [file_base], eax |
mov [file_size], ebx |
lea ebx, [hdr_cmdline] |
call test_app_header |
mov esi, -ERROR_INVALID_HEADER |
test eax, eax |
jz .err_hdr |
; The header is OK, so check for the version and if == hdrVersionConsole, patch the header with |
; the handles of the console IO socket handlers. |
mov edx, [hdr_stdio] |
mov ecx, [hdr_stderr] |
cmp [eax+APP_HEADER_02_.version], hdrVersionConsole |
jae .patch_header |
or edx, ecx |
jz .wait_lock |
mov esi, -ERROR_WRONG_HEADER_VERSION |
jmp .err_hdr |
.patch_header: |
mov [eax+APP_HEADER_02_.stdio], edx |
mov [eax+APP_HEADER_02_.stderr], ecx |
.wait_lock: |
cmp [application_table_status], 0 |
je .get_lock |
call change_task |
jmp .wait_lock |
.get_lock: |
mov eax, 1 |
xchg eax, [application_table_status] |
test eax, eax |
jnz .wait_lock |
call set_application_table_status |
call get_new_process_place |
test eax, eax |
mov esi, -ERROR_TOO_MANY_PROCESSES |
jz .err |
mov [slot], eax |
shl eax, 8 |
add eax, SLOT_BASE |
mov [slot_base], eax |
mov edi, eax |
;_clear_ 256 ;clean extended information about process |
mov ecx, 256/4 |
xor eax, eax |
cld |
rep stosd |
; write application name |
lea eax, [filename] |
stdcall strrchr, eax, '/' ; now eax points to name without path |
lea esi, [eax+1] |
test eax, eax |
jnz @F |
lea esi, [filename] |
@@: |
mov ecx, 11 ; 11 chars for name! 8 - is old value! |
mov edi, [slot_base] |
.copy_process_name_loop: |
lodsb |
cmp al, '.' |
jz .copy_process_name_done |
test al, al |
jz .copy_process_name_done |
stosb |
loop .copy_process_name_loop |
.copy_process_name_done: |
mov ebx, cr3 |
mov [save_cr3], ebx |
stdcall create_app_space, [hdr_mem], [file_base], [file_size] |
mov esi, -ERROR_MEMORY_NOT_ENOUGH ; no memory |
test eax, eax |
jz .failed |
mov ebx, [slot_base] |
mov [ebx+APPDATA.dir_table], eax |
mov eax, [hdr_mem] |
mov [ebx+APPDATA.mem_size], eax |
xor edx, edx |
cmp word [6], '02' |
jne @f |
not edx |
@@: |
mov [ebx+APPDATA.tls_base], edx |
if GREEDY_KERNEL |
else |
mov ecx, [hdr_mem] |
mov edi, [file_size] |
add edi, 4095 |
and edi, not 4095 |
sub ecx, edi |
jna @F |
xor eax, eax |
cld |
rep stosb |
@@: |
end if |
; release only virtual space, not phisical memory |
stdcall free_kernel_space, [file_base] |
lea eax, [hdr_cmdline] |
lea ebx, [cmdline] |
lea ecx, [filename] |
stdcall set_app_params , [slot], eax, ebx, ecx, [flags] |
mov eax, [save_cr3] |
call set_cr3 |
xor ebx, ebx |
mov [application_table_status], ebx;unlock application_table_status mutex |
mov eax, [process_number];set result |
jmp .final |
.failed: |
mov eax, [save_cr3] |
call set_cr3 |
.err: |
.err_hdr: |
stdcall kernel_free, [file_base] |
.err_file: |
xor eax, eax |
mov [application_table_status], eax |
mov eax, esi |
.final: |
cmp [SCR_MODE], word 0x13 |
jbe @f |
pushad |
stdcall set_cursor, [handle] |
mov [redrawmouse_unconditional], 1 |
call __sys_draw_pointer |
popad |
@@: |
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+0x08], ecx ;app_eip |
mov edx, [APP_HEADER_00.mem_size] |
mov [ebx+0x10], edx ;app_mem |
shr edx, 1 |
sub edx, 0x10 |
mov [ebx+0x0C], edx ;app_esp |
mov ecx, [APP_HEADER_00.i_param] |
mov [ebx], ecx ;app_cmdline |
mov [ebx+4], dword 0 ;app_path |
mov edx, [APP_HEADER_00.i_end] |
mov [ebx+0x14], 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 ;app_eip |
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+0x10], edx ;app_mem |
mov ecx, [APP_HEADER_01.stack_top] |
mov [ebx+0x0C], ecx ;app_esp |
mov edx, [APP_HEADER_01.i_param] |
mov [ebx], edx ;app_cmdline |
mov ecx, [APP_HEADER_01.i_icon] |
mov [ebx+4], ecx ;app_path |
mov edx, [APP_HEADER_01.i_end] |
mov [ebx+0x14], edx |
ret |
.fail: |
xor eax, eax |
ret |
align 4 |
proc get_new_process_place |
;input: |
; none |
;result: |
; eax=[new_process_place]<>0 - ok |
; 0 - failed. |
;This function find least empty slot. |
;It doesn't increase [TASK_COUNT]! |
mov eax, CURRENT_TASK |
mov ebx, [TASK_COUNT] |
inc ebx |
shl ebx, 5 |
add ebx, eax ;ebx - address of process information for (last+1) slot |
.newprocessplace: |
;eax = address of process information for current slot |
cmp eax, ebx |
jz .endnewprocessplace ;empty slot after high boundary |
add eax, 0x20 |
cmp word [eax+0xa], 9;check process state, 9 means that process slot is empty |
jnz .newprocessplace |
.endnewprocessplace: |
mov ebx, eax |
sub eax, CURRENT_TASK |
shr eax, 5 ;calculate slot index |
cmp eax, 256 |
jge .failed ;it should be <256 |
mov word [ebx+0xa], 9;set process state to 9 (for slot after hight boundary) |
ret |
.failed: |
xor eax, eax |
ret |
endp |
align 4 |
proc create_app_space stdcall, app_size:dword,img_base:dword,img_size:dword |
locals |
app_pages dd ? |
img_pages dd ? |
dir_addr dd ? |
app_tabs dd ? |
endl |
mov ecx, pg_data.mutex |
call mutex_lock |
xor eax, eax |
mov [dir_addr], eax |
mov eax, [app_size] |
add eax, 4095 |
and eax, NOT(4095) |
mov [app_size], eax |
mov ebx, eax |
shr eax, 12 |
mov [app_pages], eax |
add ebx, 0x3FFFFF |
and ebx, NOT(0x3FFFFF) |
shr ebx, 22 |
mov [app_tabs], ebx |
mov ecx, [img_size] |
add ecx, 4095 |
and ecx, NOT(4095) |
mov [img_size], ecx |
shr ecx, 12 |
mov [img_pages], ecx |
if GREEDY_KERNEL |
lea eax, [ecx+ebx+2];only image size |
else |
lea eax, [eax+ebx+2];all requested memory |
end if |
cmp eax, [pg_data.pages_free] |
ja .fail |
call alloc_page |
test eax, eax |
jz .fail |
mov [dir_addr], eax |
stdcall map_page, [tmp_task_pdir], eax, dword PG_SW |
mov edi, [tmp_task_pdir] |
mov ecx, (OS_BASE shr 20)/4 |
xor eax, eax |
cld |
rep stosd |
mov ecx, (OS_BASE shr 20)/4 |
mov esi, sys_pgdir+(OS_BASE shr 20) |
rep movsd |
mov eax, [dir_addr] |
or eax, PG_SW |
mov [edi-4096+(page_tabs shr 20)], eax |
and eax, -4096 |
call set_cr3 |
mov edx, [app_tabs] |
mov edi, new_app_base |
@@: |
call alloc_page |
test eax, eax |
jz .fail |
stdcall map_page_table, edi, eax |
add edi, 0x00400000 |
dec edx |
jnz @B |
mov edi, new_app_base |
shr edi, 10 |
add edi, page_tabs |
mov ecx, [app_tabs] |
shl ecx, 10 |
xor eax, eax |
rep stosd |
mov ecx, [img_pages] |
mov ebx, PG_UW |
mov edx, new_app_base |
mov esi, [img_base] |
mov edi, new_app_base |
shr esi, 10 |
shr edi, 10 |
add esi, page_tabs |
add edi, page_tabs |
.remap: |
lodsd |
or eax, ebx; force user level r/w access |
stosd |
add edx, 0x1000 |
dec [app_pages] |
dec ecx |
jnz .remap |
mov ecx, [app_pages] |
test ecx, ecx |
jz .done |
if GREEDY_KERNEL |
mov eax, 0x02 |
rep stosd |
else |
.alloc: |
call alloc_page |
test eax, eax |
jz .fail |
stdcall map_page, edx, eax, dword PG_UW |
add edx, 0x1000 |
dec [app_pages] |
jnz .alloc |
end if |
.done: |
stdcall map_page, [tmp_task_pdir], dword 0, dword PG_UNMAP |
mov ecx, pg_data.mutex |
call mutex_unlock |
mov eax, [dir_addr] |
ret |
.fail: |
mov ecx, pg_data.mutex |
call mutex_unlock |
cmp [dir_addr], 0 |
je @f |
stdcall destroy_app_space, [dir_addr], 0 |
@@: |
xor eax, eax |
ret |
endp |
align 4 |
set_cr3: |
mov ebx, [current_slot] |
mov [ebx+APPDATA.dir_table], eax |
mov cr3, eax |
ret |
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, 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 |
proc destroy_app_space stdcall, pg_dir:dword, dlls_list:dword |
xor edx, edx |
push edx |
mov eax, 0x2 |
mov ebx, [pg_dir] |
.loop: |
;eax = current slot of process |
mov ecx, eax |
shl ecx, 5 |
cmp byte [CURRENT_TASK+ecx+0xa], 9;if process running? |
jz @f ;skip empty slots |
shl ecx, 3 |
add ecx, SLOT_BASE |
cmp [ecx+APPDATA.dir_table], ebx;compare page directory addresses |
jnz @f |
mov [ebp-4], ecx |
inc edx ;thread found |
@@: |
inc eax |
cmp eax, [TASK_COUNT] ;exit loop if we look through all processes |
jle .loop |
;edx = number of threads |
;our process is zombi so it isn't counted |
pop ecx |
cmp edx, 1 |
jg .ret |
;if there isn't threads then clear memory. |
mov esi, [dlls_list] |
call destroy_all_hdlls;ecx=APPDATA |
mov ecx, pg_data.mutex |
call mutex_lock |
mov eax, [pg_dir] |
and eax, not 0xFFF |
stdcall map_page, [tmp_task_pdir], eax, PG_SW |
mov esi, [tmp_task_pdir] |
mov edi, (OS_BASE shr 20)/4 |
.destroy: |
mov eax, [esi] |
test eax, 1 |
jz .next |
and eax, not 0xFFF |
stdcall map_page, [tmp_task_ptab], eax, PG_SW |
stdcall destroy_page_table, [tmp_task_ptab] |
mov eax, [esi] |
call free_page |
.next: |
add esi, 4 |
dec edi |
jnz .destroy |
mov eax, [pg_dir] |
call free_page |
.exit: |
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP |
stdcall map_page, [tmp_task_pdir], 0, PG_UNMAP |
mov ecx, pg_data.mutex |
call mutex_unlock |
.ret: |
ret |
endp |
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, [TASK_COUNT] |
shl ebx, 5 |
mov ecx, 2*32 |
.loop: |
;ecx=offset of current process info entry |
;ebx=maximum permitted offset |
cmp byte [CURRENT_TASK+ecx+0xa], 9 |
jz .endloop ;skip empty slots |
cmp [CURRENT_TASK+ecx+0x4], eax;check PID |
jz .pid_found |
.endloop: |
add ecx, 32 |
cmp ecx, ebx |
jle .loop |
pop ecx |
pop ebx |
xor eax, eax |
ret |
.pid_found: |
shr ecx, 5 |
mov eax, ecx ;convert offset to index of slot |
pop ecx |
pop ebx |
ret |
check_region: |
;input: |
; esi - start of buffer |
; edx - size of buffer |
;result: |
; eax = 1 region lays in app memory |
; eax = 0 region don't lays in app memory |
mov eax, [CURRENT_TASK] |
; jmp check_process_region |
;----------------------------------------------------------------------------- |
;check_process_region: |
;input: |
; eax - slot |
; esi - start of buffer |
; edx - size of buffer |
;result: |
; eax = 1 region lays in app memory |
; eax = 0 region don't lays in app memory |
test edx, edx |
jle .ok |
shl eax, 5 |
cmp word [CURRENT_TASK+eax+0xa], 0 |
jnz .failed |
shl eax, 3 |
mov eax, [SLOT_BASE+eax+0xb8] |
test eax, eax |
jz .failed |
mov eax, 1 |
ret |
; call MEM_Get_Linear_Address |
; push ebx |
; push ecx |
; push edx |
; mov edx,ebx |
; and edx,not (4096-1) |
; sub ebx,edx |
; add ecx,ebx |
; mov ebx,edx |
; add ecx,(4096-1) |
; and ecx,not (4096-1) |
;.loop: |
;;eax - linear address of page directory |
;;ebx - current page |
;;ecx - current size |
; mov edx,ebx |
; shr edx,22 |
; mov edx,[eax+4*edx] |
; and edx,not (4096-1) |
; test edx,edx |
; jz .failed1 |
; push eax |
; mov eax,edx |
; call MEM_Get_Linear_Address |
; mov edx,ebx |
; shr edx,12 |
; and edx,(1024-1) |
; mov eax,[eax+4*edx] |
; and eax,not (4096-1) |
; test eax,eax |
; pop eax |
; jz .failed1 |
; add ebx,4096 |
; sub ecx,4096 |
; jg .loop |
; pop edx |
; pop ecx |
; pop ebx |
.ok: |
mov eax, 1 |
ret |
; |
;.failed1: |
; pop edx |
; pop ecx |
; pop ebx |
.failed: |
xor eax, eax |
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_MAP |
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] |
; add ebx, new_app_base |
push ecx |
stdcall map_memEx, [proc_mem_map], \ |
[slot], ebx, ecx, PG_SW |
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 |
align 4 |
proc new_sys_threads |
locals |
slot dd ? |
app_cmdline dd ? ;0x00 |
app_path dd ? ;0x04 |
app_eip dd ? ;0x08 |
app_esp dd ? ;0x0C |
app_mem dd ? ;0x10 |
endl |
cmp ebx, 1 |
jne .failed ;other subfunctions |
xor eax, eax |
mov [app_eip], ecx |
mov [app_cmdline], eax |
mov [app_esp], edx |
mov [app_path], eax |
;mov esi,new_process_loading |
;call sys_msg_board_str |
.wait_lock: |
cmp [application_table_status], 0 |
je .get_lock |
call change_task |
jmp .wait_lock |
.get_lock: |
mov eax, 1 |
xchg eax, [application_table_status] |
test eax, eax |
jnz .wait_lock |
call set_application_table_status |
call get_new_process_place |
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, 256/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.heap_base] |
mov [edx+APPDATA.heap_base], eax |
mov ecx, [ebx+APPDATA.heap_top] |
mov [edx+APPDATA.heap_top], ecx |
mov eax, [ebx+APPDATA.mem_size] |
mov [edx+APPDATA.mem_size], eax |
mov ecx, [ebx+APPDATA.dir_table] |
mov [edx+APPDATA.dir_table], ecx;copy page directory |
mov eax, [ebx+APPDATA.dlls_list_ptr] |
mov [edx+APPDATA.dlls_list_ptr], eax |
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 |
lea eax, [app_cmdline] |
stdcall set_app_params , [slot], eax, dword 0, \ |
dword 0,dword 0 |
;mov esi,new_process_running |
;call sys_msg_board_str ;output information about succefull startup |
xor eax, eax |
mov [application_table_status], eax ;unlock application_table_status mutex |
mov eax, [process_number] ;set result |
ret |
.failed: |
xor eax, eax |
.failed1: |
mov [application_table_status], eax |
dec eax ;-1 |
ret |
endp |
align 4 |
tls_app_entry: |
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 |
popad |
iretd |
EFL_IF equ 0x0200 |
EFL_IOPL1 equ 0x1000 |
EFL_IOPL2 equ 0x2000 |
EFL_IOPL3 equ 0x3000 |
align 4 |
proc set_app_params stdcall,slot:dword, params:dword,\ |
cmd_line:dword, app_path:dword, flags:dword |
locals |
pl0_stack dd ? |
endl |
stdcall kernel_alloc, RING0_STACK_SIZE+512 |
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+256+APPDATA.io_map] |
mov [eax+SLOT_BASE+APPDATA.io_map], ecx |
mov ecx, [SLOT_BASE+256+APPDATA.io_map+4] |
mov [eax+SLOT_BASE+APPDATA.io_map+4], ecx |
mov esi, fpu_data |
mov ecx, 512/4 |
rep movsd |
cmp ebx, [TASK_COUNT] |
jle .noinc |
inc dword [TASK_COUNT] ;update number of processes |
.noinc: |
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, 0x1000 |
pop ebx |
mov esi, [current_slot] |
mov esi, [esi+APPDATA.cur_dir] |
mov ecx, 0x1000/4 |
mov edi, eax |
mov [ebx+SLOT_BASE+APPDATA.cur_dir], eax |
rep movsd |
shr ebx, 3 |
mov eax, new_app_base |
mov dword [CURRENT_TASK+ebx+0x10], eax |
.add_command_line: |
mov edx, [params] |
mov edx, [edx] ;app_cmdline |
test edx, edx |
jz @f ;application doesn't need parameters |
mov eax, edx |
add eax, 256 |
jc @f |
cmp eax, [SLOT_BASE+APPDATA.mem_size+ebx*8] |
ja @f |
mov byte [edx], 0 ;force empty string if no cmdline given |
mov eax, [cmd_line] |
test eax, eax |
jz @f |
stdcall strncpy, edx, eax, 256 |
@@: |
mov edx, [params] |
mov edx, [edx+4];app_path |
test edx, edx |
jz @F ;application don't need path of file |
mov eax, edx |
add eax, 1024 |
jc @f |
cmp eax, [SLOT_BASE+APPDATA.mem_size+ebx*8] |
ja @f |
stdcall strncpy, edx, [app_path], 1024 |
@@: |
mov ebx, [slot] |
mov eax, ebx |
shl ebx, 5 |
lea ecx, [draw_data+ebx];ecx - pointer to draw data |
mov edx, irq0.return |
cmp [ebx*8+SLOT_BASE+APPDATA.tls_base], -1 |
jne @F |
mov edx, tls_app_entry |
@@: |
; 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, CURRENT_TASK ;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+4], 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_Max_X] |
mov [ecx+8], eax |
mov eax, [Screen_Max_Y] |
mov [ecx+12], eax |
mov ebx, [pl0_stack] |
mov esi, [params] |
lea ecx, [ebx+REG_EIP] |
xor eax, eax |
mov [ebx+REG_RET], edx |
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+0x08] ;app_eip |
mov [ebx+REG_EIP], eax;app_entry |
mov [ebx+REG_CS], dword app_code |
mov eax, [CURRENT_TASK] |
shl eax, 8 ; created by kernel? |
cmp [SLOT_BASE+eax+APPDATA.dir_table], sys_pgdir - OS_BASE |
jnz @f |
cmp [app_path], 0 ; it is a thread? |
jnz @f |
mov [ebx+REG_CS], dword os_code ; kernel thread |
@@: |
mov [ebx+REG_EFLAGS], dword EFL_IOPL1+EFL_IF |
mov eax, [esi+0x0C] ;app_esp |
mov [ebx+REG_APP_ESP], eax;app_stack |
mov [ebx+REG_SS], dword app_data |
lea ecx, [ebx+REG_RET] |
mov ebx, [slot] |
shl ebx, 5 |
mov [ebx*8+SLOT_BASE+APPDATA.saved_esp], ecx |
xor ecx, ecx; process state - running |
; set if debuggee |
test byte [flags], 1 |
jz .no_debug |
inc ecx ; process state - suspended |
mov eax, [CURRENT_TASK] |
mov [SLOT_BASE+ebx*8+APPDATA.debugger_slot], eax |
.no_debug: |
mov [CURRENT_TASK+ebx+TASKDATA.state], cl |
;mov esi,new_process_running |
;call sys_msg_board_str ;output information about succefull startup |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/test_malloc.asm |
---|
0,0 → 1,249 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2009-2011. 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 '../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:mergeinfo |
/kernel/branches/net/core/timers.inc |
---|
0,0 → 1,205 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2381 $ |
; 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_TASK] |
@@: |
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. |
push sizeof.TIMER |
pop eax |
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 |
/kernel/branches/net/core/exports.inc |
---|
0,0 → 1,201 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
iglobal |
szKernel db 'KERNEL', 0 |
szVersion db 'version',0 |
szRegService db 'RegService',0 |
szGetService db 'GetService',0 |
szServiceHandler db 'ServiceHandler',0 |
szAttachIntHandler db 'AttachIntHandler',0 |
; szGetIntHandler db 'GetIntHandler', 0 |
szFpuSave db 'FpuSave',0 |
szFpuRestore db 'FpuRestore',0 |
szReservePortArea db 'ReservePortArea',0 |
szBoot_Log db 'Boot_Log',0 |
szMutexInit db 'MutexInit',0 |
szMutexLock db 'MutexLock',0 |
szMutexUnlock db 'MutexUnlock',0 |
szPciApi db 'PciApi', 0 |
szPciRead32 db 'PciRead32', 0 |
szPciRead16 db 'PciRead16', 0 |
szPciRead8 db 'PciRead8', 0 |
szPciWrite8 db 'PciWrite8',0 |
szPciWrite16 db 'PciWrite16',0 |
szPciWrite32 db 'PciWrite32',0 |
szAllocPage db 'AllocPage',0 |
szAllocPages db 'AllocPages',0 |
szFreePage db 'FreePage',0 |
szGetPgAddr db 'GetPgAddr',0 |
szMapPage db 'MapPage',0 |
szMapSpace db 'MapSpace',0 |
szMapIoMem db 'MapIoMem',0 |
szCommitPages db 'CommitPages',0 |
szReleasePages db 'ReleasePages',0 |
szAllocKernelSpace db 'AllocKernelSpace',0 |
szFreeKernelSpace db 'FreeKernelSpace',0 |
szKernelAlloc db 'KernelAlloc',0 |
szKernelFree db 'KernelFree',0 |
szUserAlloc db 'UserAlloc',0 |
szUserFree db 'UserFree',0 |
szKmalloc db 'Kmalloc',0 |
szKfree db 'Kfree',0 |
szCreateRingBuffer db 'CreateRingBuffer',0 |
szGetPid db 'GetPid',0 |
szCreateObject db 'CreateObject',0 |
szDestroyObject db 'DestroyObject',0 |
szCreateEvent db 'CreateEvent',0 |
szRaiseEvent db 'RaiseEvent',0 |
szWaitEvent db 'WaitEvent',0 |
szDestroyEvent db 'DestroyEvent',0 |
szClearEvent db 'ClearEvent',0 |
szLoadCursor db 'LoadCursor',0 |
szSysMsgBoardStr db 'SysMsgBoardStr', 0 |
szSysMsgBoardChar db 'SysMsgBoardChar', 0 |
szGetCurrentTask db 'GetCurrentTask',0 |
szLFBAddress db 'LFBAddress',0 |
szLoadFile db 'LoadFile',0 |
szSendEvent db 'SendEvent',0 |
szSetMouseData db 'SetMouseData',0 |
szSetKeyboardData db 'SetKeyboardData',0 |
szRegKeyboard db 'RegKeyboard',0 |
szDelKeyboard db 'DelKeyboard',0 |
szSleep db 'Sleep',0 |
szGetTimerTicks db 'GetTimerTicks',0 |
szGetDisplay db 'GetDisplay',0 |
szSetScreen db 'SetScreen',0 |
szStrncat db 'strncat',0 |
szStrncpy db 'strncpy',0 |
szstrncmp db 'strncmp',0 |
szStrnlen db 'strnlen',0 |
szStrchr db 'strchr',0 |
szStrrchr db 'strrchr',0 |
szDiskAdd db 'DiskAdd',0 |
szDiskDel db 'DiskDel',0 |
szDiskMediaChanged db 'DiskMediaChanged',0 |
szTimerHS db 'TimerHS',0 |
szCancelTimerHS db 'CancelTimerHS',0 |
szNetRegDev db 'NetRegDev',0 |
szNetUnRegDev db 'NetUnRegDev',0 |
szNetPtrToNum db 'NetPtrToNum',0 |
szNetLinkChanged db 'NetLinkChanged',0 |
szEth_input db 'Eth_input',0 |
szIPv4_input db 'IPv4_input',0 |
align 16 |
kernel_export: |
dd szRegService , reg_service |
dd szGetService , get_service |
dd szServiceHandler , srv_handler |
dd szAttachIntHandler, attach_int_handler |
; dd szGetIntHandler , get_int_handler |
dd szFpuSave , fpu_save |
dd szFpuRestore , fpu_restore |
dd szReservePortArea , r_f_port_area |
dd szBoot_Log , boot_log |
dd szMutexInit , mutex_init ;gcc fastcall |
dd szMutexLock , mutex_lock ;gcc fastcall |
dd szMutexUnlock , mutex_unlock ;gcc fastcall |
dd szPciApi , pci_api_drv |
dd szPciRead32 , pci_read32 |
dd szPciRead16 , pci_read16 |
dd szPciRead8 , pci_read8 |
dd szPciWrite8 , pci_write8 |
dd szPciWrite16 , pci_write16 |
dd szPciWrite32 , pci_write32 |
dd szAllocPage , alloc_page ;stdcall |
dd szAllocPages , alloc_pages ;stdcall |
dd szFreePage , free_page |
dd szMapPage , map_page ;stdcall |
dd szMapSpace , map_space |
dd szMapIoMem , map_io_mem ;stdcall |
dd szGetPgAddr , get_pg_addr |
dd szCommitPages , commit_pages ;not implemented |
dd szReleasePages , release_pages |
dd szAllocKernelSpace, alloc_kernel_space ;stdcall |
dd szFreeKernelSpace , free_kernel_space ;stdcall |
dd szKernelAlloc , kernel_alloc ;stdcall |
dd szKernelFree , kernel_free ;stdcall |
dd szUserAlloc , user_alloc ;stdcall |
dd szUserFree , user_free ;stdcall |
dd szKmalloc , malloc |
dd szKfree , free |
dd szCreateRingBuffer, create_ring_buffer ;stdcall |
dd szGetPid , get_pid |
dd szCreateObject , create_kernel_object |
dd szDestroyObject , destroy_kernel_object |
dd szCreateEvent , create_event ;see EVENT.inc for specification |
dd szRaiseEvent , raise_event ;see EVENT.inc for specification |
dd szWaitEvent , wait_event ;see EVENT.inc for specification |
dd szDestroyEvent , destroy_event ;see EVENT.inc for specification |
dd szClearEvent , clear_event ;see EVENT.inc for specification |
dd szLoadCursor , load_cursor ;stdcall |
dd szSysMsgBoardStr , sys_msg_board_str |
dd szSysMsgBoardChar , sys_msg_board |
dd szGetCurrentTask , get_curr_task |
dd szLoadFile , load_file ;retval eax, ebx |
dd szSendEvent , send_event ;see EVENT.inc for specification |
dd szSetMouseData , set_mouse_data ;stdcall |
dd szSetKeyboardData , set_keyboard_data |
dd szRegKeyboard , register_keyboard |
dd szDelKeyboard , delete_keyboard |
dd szSleep , delay_ms |
dd szGetTimerTicks , get_timer_ticks |
dd szGetDisplay , get_display |
dd szSetScreen , set_screen |
dd szStrncat , strncat |
dd szStrncpy , strncpy |
dd szstrncmp , strncmp |
dd szStrnlen , strnlen |
dd szStrchr , strchr |
dd szStrrchr , strrchr |
dd szDiskAdd , disk_add |
dd szDiskDel , disk_del |
dd szDiskMediaChanged, disk_media_changed |
dd szTimerHS , timer_hs |
dd szCancelTimerHS , cancel_timer_hs |
dd szNetRegDev , NET_add_device |
dd szNetUnRegDev , NET_remove_device |
dd szNetPtrToNum , NET_ptr_to_num |
dd szNetLinkChanged , NET_link_changed |
dd szEth_input , ETH_input |
dd szIPv4_input , IPv4_input |
exp_lfb: |
dd szLFBAddress , 0 |
dd 0 ;terminator, must be zero |
endg |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/debug.inc |
---|
0,0 → 1,435 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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_TASK] |
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 |
cli |
mov eax, ecx |
call pid_to_slot |
shl eax, 5 |
jz .ret |
mov cl, [CURRENT_TASK+eax+TASKDATA.state] ; process state |
test cl, cl |
jz .1 |
cmp cl, 5 |
jnz .ret |
mov cl, 2 |
.2: |
mov [CURRENT_TASK+eax+TASKDATA.state], cl |
.ret: |
sti |
ret |
.1: |
inc ecx |
jmp .2 |
do_resume: |
mov cl, [CURRENT_TASK+eax+TASKDATA.state] |
cmp cl, 1 |
jz .1 |
cmp cl, 2 |
jnz .ret |
mov cl, 5 |
.2: |
mov [CURRENT_TASK+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,ecx,edx,esi,edi |
cmp edx, 28h |
jnz .ret |
; push ecx |
; mov ecx, esi |
call check_region |
; pop ecx |
dec eax |
jnz .ret |
call get_debuggee_slot |
jc .ret |
mov edi, esi |
mov eax, [eax*8+SLOT_BASE+APPDATA.pl0_stack] |
lea esi, [eax+RING0_STACK_SIZE] |
.ring0: |
; note that following code assumes that all interrupt/exception handlers |
; saves 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 |
.ret: |
sti |
ret |
debug_setcontext: |
; in: |
; ecx=pid |
; edx=sizeof(CONTEXT) |
; esi->CONTEXT |
; destroys eax,ecx,edx,esi,edi |
cmp edx, 28h |
jnz .ret |
; push ebx |
; mov ebx, edx |
call check_region |
; pop ebx |
dec eax |
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 |
; push ebx |
; mov ebx, esi |
call check_region |
; pop ebx |
dec eax |
jnz .err |
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 |
; push ebx |
; mov ebx, esi |
call check_region |
; pop ebx |
dec eax |
jnz debug_read_process_memory.err |
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_TASK], 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, 8 |
or byte [SLOT_BASE+eax+APPDATA.event_mask+1], 1 ; set flag 100h |
.ret: |
ret |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/export.inc |
---|
0,0 → 1,40 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/ext_lib.inc |
---|
0,0 → 1,333 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;============================================================================ |
; |
; External kernel dependencies (libraries) loading |
; |
;============================================================================ |
$Revision $ |
if 0 |
; The code currently does not work. Kill "if 0/end if" only after correcting |
; to current kernel (dll.inc). |
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 |
uglobal |
s_libname db 64 dup (0) |
endg |
end if |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/fpu.inc |
---|
0,0 → 1,183 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
init_fpu: |
clts |
fninit |
bt [cpu_caps], CAPS_SSE |
jnc .no_SSE |
mov ebx, cr4 |
mov ecx, cr0 |
or ebx, CR4_OSFXSR+CR4_OSXMMEXPT |
mov cr4, ebx |
and ecx, not (CR0_MP+CR0_EM) |
or ecx, CR0_NE |
mov cr0, ecx |
mov dword [esp-4], SSE_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 |
fxsave [fpu_data] ;[eax] |
ret |
.no_SSE: |
mov ecx, cr0 |
and ecx, not CR0_EM |
or ecx, CR0_MP+CR0_NE |
mov cr0, ecx |
fnsave [fpu_data] |
ret |
; param |
; eax= 512 bytes memory area |
align 4 |
fpu_save: |
push ecx |
push esi |
push edi |
pushfd |
cli |
clts |
mov edi, eax |
mov ecx, [fpu_owner] |
mov esi, [CURRENT_TASK] |
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, 512/4 |
cld |
rep movsd |
fninit |
.exit: |
popfd |
pop edi |
pop esi |
pop ecx |
ret |
align 4 |
save_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_TASK] |
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 |
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_TASK] |
je .exit |
shl ebx, 8 |
mov eax, [ebx+SLOT_BASE+APPDATA.fpu_state] |
bt [cpu_caps], CAPS_SSE |
jnc .no_SSE |
fxsave [eax] |
mov ebx, [CURRENT_TASK] |
mov [fpu_owner], ebx |
shl ebx, 8 |
mov eax, [ebx+SLOT_BASE+APPDATA.fpu_state] |
fxrstor [eax] |
.exit: |
restore_ring3_context |
iret |
.no_SSE: |
fnsave [eax] |
mov ebx, [CURRENT_TASK] |
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 0 |
endg |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/sched.inc |
---|
0,0 → 1,400 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 ds, ax, app_data |
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 |
btr dword[DONT_SWITCH], 0 |
jc .return |
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 |
if 0 |
; \begin{Mario79} ; <- must be refractoried, if used... |
cmp [dma_task_switched], 1 |
jne .find_next_task |
mov [dma_task_switched], 0 |
mov ebx, [dma_process] |
cmp [CURRENT_TASK], ebx |
je .return |
mov edi, [dma_slot_ptr] |
mov [CURRENT_TASK], ebx |
mov [TASK_BASE], edi |
jmp @f |
.find_next_task: |
; \end{Mario79} |
end if |
call find_next_task |
jz .return ; the same task -> skip switch |
@@: |
mov byte[DONT_SWITCH], 1 |
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: |
xor eax, eax |
xchg eax, [idleuse] |
mov [idleusesec], eax |
mov ecx, [TASK_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 |
align 4 |
find_next_task: |
;info: |
; Find next task to execute |
;retval: |
; ebx = address of the APPDATA for the selected task (slot-base) |
; esi = previous slot-base ([current_slot] at the begin) |
; edi = address of the TASKDATA for the selected task |
; ZF = 1 if the task is the same |
;warning: |
; [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result |
; [current_slot] is not set to new value (ebx)!!! |
;scratched: eax,ecx |
call update_counters ; edi := [TASK_BASE] |
Mov esi, ebx, [current_slot] |
.loop: |
cmp bh, [TASK_COUNT] |
jb @f |
xor bh, bh |
mov edi, CURRENT_TASK |
@@: |
inc bh ; ebx += APPDATA.size |
add edi, 0x20; edi += TASKDATA.size |
mov al, [edi+TASKDATA.state] |
test al, al |
jz .found ; state == 0 |
cmp al, 5 |
jne .loop ; 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 ecx, [timer_ticks] |
sub ecx, [ebx+APPDATA.wait_begin] |
cmp ecx, [ebx+APPDATA.wait_timeout] |
jb .loop |
@@: |
mov [ebx+APPDATA.wait_param], eax ; retval for wait |
mov [edi+TASKDATA.state], 0 |
.found: |
mov [CURRENT_TASK], bh |
mov [TASK_BASE], edi |
rdtsc ;call _rdtsc |
mov [edi+TASKDATA.counter_add], eax; for next using update_counters |
cmp ebx, esi ;esi - previous slot-base |
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_TASK] 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 dword [page_tabs+((tss._io_map_0 and -4096) shr 10)],eax,[ebx+APPDATA.io_map] |
Mov dword [page_tabs+((tss._io_map_1 and -4096) shr 10)],eax,[ebx+APPDATA.io_map+4] |
; set new thread memory-map |
mov ecx, APPDATA.dir_table |
mov eax, [ebx+ecx] ;offset>0x7F |
cmp eax, [esi+ecx] ;offset>0x7F |
je @f |
mov cr3, eax |
@@: |
; set tss.esp0 |
Mov [tss._esp0],eax,[ebx+APPDATA.saved_esp0] |
mov edx, [ebx+APPDATA.tls_base] |
cmp edx, [esi+APPDATA.tls_base] |
je @f |
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 gs,ax,graph_data |
; 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+ecx+APPDATA.dbg_regs-APPDATA.dir_table];offset>0x7F |
cld |
macro lodsReg [reg] { |
lodsd |
mov reg, eax |
} lodsReg dr0, dr1, dr2, dr3, dr7 |
purge lodsReg |
@@: |
ret |
;end. |
struct MUTEX_WAITER |
list LHEAD |
task dd ? |
ends |
;void __fastcall mutex_init(struct mutex *lock) |
align 4 |
mutex_init: |
mov [ecx+MUTEX.lhead.next], ecx |
mov [ecx+MUTEX.lhead.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], 1 |
call change_task |
jmp .forever |
@@: |
mov edx, [esp+MUTEX_WAITER.list.next] |
mov eax, [esp+MUTEX_WAITER.list.prev] |
mov [eax+MUTEX_WAITER.list.next], edx |
mov [edx+MUTEX_WAITER.list.prev], eax |
cmp [ecx+MUTEX.lhead.next], ecx |
jne @F |
mov [ecx+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.lhead.next] |
cmp eax, ecx |
mov [ecx+MUTEX.count], 1 |
je @F |
mov eax, [eax+MUTEX_WAITER.task] |
mov [eax+TASKDATA.state], 0 |
@@: |
popfd |
ret |
purge MUTEX_WAITER |
if 0 |
struc TIMER |
{ |
.next dd ? |
.exp_time dd ? |
.func dd ? |
.arg dd ? |
} |
MAX_PROIRITY 0 ; highest, used for kernel tasks |
MAX_USER_PRIORITY 0 ; highest priority for user processes |
USER_PRIORITY 7 ; default (should correspond to nice 0) |
MIN_USER_PRIORITY 14 ; minimum priority for user processes |
IDLE_PRIORITY 15 ; lowest, only IDLE process goes here |
NR_SCHED_QUEUES 16 ; MUST equal IDLE_PRIORYTY + 1 |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/string.inc |
---|
0,0 → 1,188 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core/sync.inc |
---|
0,0 → 1,119 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Synhronization for MenuetOS. ;; |
;; Author: Halyavin Andrey, halyavin@land.ru ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/core |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/fs/ext2.inc |
---|
0,0 → 1,1238 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; 02.02.2010 turbanoff - support 70.5 ;; |
;; 23.01.2010 turbanoff - support 70.0 70.1 ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2381 $ |
EXT2_BAD_INO = 1 |
EXT2_ROOT_INO = 2 |
EXT2_ACL_IDX_INO = 3 |
EXT2_ACL_DATA_INO = 4 |
EXT2_BOOT_LOADER_INO = 5 |
EXT2_UNDEL_DIR_INO = 6 |
;флаги, указываемый в inode файла |
EXT2_S_IFREG = 0x8000 |
EXT2_S_IFDIR = 0x4000 |
EXT2_S_IFMT = 0xF000 ;маска для типа файла |
;флаги, указываемые в linked list родительской папки |
EXT2_FT_REG_FILE = 1 ;это файл, запись в родительском каталоге |
EXT2_FT_DIR = 2 ;это папка |
;флаги используемые KolibriOS |
FS_FT_HIDDEN = 2 |
FS_FT_DIR = 0x10 ;это папка |
FS_FT_ASCII = 0 ;имя в ascii |
FS_FT_UNICODE = 1 ;имя в unicode |
EXT2_FEATURE_INCOMPAT_FILETYPE = 0x0002 ;тип файла должен указываться в директории |
EXT4_FEATURE_INCOMPAT_EXTENTS = 0x0040 ;экстенты |
EXT4_FEATURE_INCOMPAT_FLEX_BG = 0x0200 ;гибкие группы блоков |
;реализованные ext[234] features |
EXT4_FEATURE_INCOMPAT_SUPP = EXT2_FEATURE_INCOMPAT_FILETYPE \ |
or EXT4_FEATURE_INCOMPAT_EXTENTS \ |
or EXT4_FEATURE_INCOMPAT_FLEX_BG |
;флаги, указываемые для inode в i_flags |
EXT2_EXTENTS_FL = 0x00080000 |
struct EXT2_INODE_STRUC |
i_mode dw ? |
i_uid dw ? |
i_size dd ? |
i_atime dd ? |
i_ctime dd ? |
i_mtime dd ? |
i_dtime dd ? |
i_gid dw ? |
i_links_count dw ? |
i_blocks dd ? |
i_flags dd ? |
i_osd1 dd ? |
i_block rd 15 |
i_generation dd ? |
i_file_acl dd ? |
i_dir_acl dd ? |
i_faddr dd ? |
i_osd2 dd ? ; 1..12 |
ends |
struct EXT2_DIR_STRUC |
inode dd ? |
rec_len dw ? |
name_len db ? |
file_type db ? |
name db ? ; 0..255 |
ends |
struct EXT2_BLOCK_GROUP_DESC |
block_bitmap dd ? ;+0 |
inode_bitmap dd ? ;+4 |
inode_table dd ? ;+8 |
free_blocks_count dw ? ;+12 |
free_inodes_count dw ? ;+14 |
used_dirs_count dw ? ;+16 |
pad dw ? ;+18 |
reserved rb 12;+20 |
ends |
struct EXT2_SB_STRUC |
inodes_count dd ? ;+0 |
blocks_count dd ? ;+4 |
r_block_count dd ? ;+8 |
free_block_count dd ? ;+12 |
free_inodes_count dd ? ;+16 |
first_data_block dd ? ;+20 |
log_block_size dd ? ;+24 |
log_frag_size dd ? ;+28 |
blocks_per_group dd ? ;+32 |
frags_per_group dd ? ;+36 |
inodes_per_group dd ? ;+40 |
mtime dd ? ;+44 |
wtime dd ? ;+48 |
mnt_count dw ? ;+52 |
max_mnt_count dw ? ;+54 |
magic dw ? ;+56 |
state dw ? ;+58 |
errors dw ? ;+60 |
minor_rev_level dw ? ;+62 |
lastcheck dd ? ;+64 |
check_intervals dd ? ;+68 |
creator_os dd ? ;+72 |
rev_level dd ? ;+76 |
def_resuid dw ? ;+80 |
def_resgid dw ? ;+82 |
first_ino dd ? ;+84 |
inode_size dw ? ;+88 |
block_group_nr dw ? ;+90 |
feature_compat dd ? ;+92 |
feature_incompat dd ? ;+96 |
feature_ro_compat dd ? ;+100 |
uuid rb 16 ;+104 |
volume_name rb 16 ;+120 |
last_mounted rb 64 ;+136 |
algo_bitmap dd ? ;+200 |
prealloc_blocks db ? ;+204 |
preallock_dir_blocks db ? ;+205 |
reserved_gdt_blocks dw ? ;+206 |
journal_uuid rb 16 ;+208 |
journal_inum dd ? ;+224 |
journal_dev dd ? ;+228 |
last_orphan dd ? ;+232 |
hash_seed rd 4 ;+236 |
def_hash_version db ? ;+252 |
rb 3 ;+253 reserved |
default_mount_options dd ? ;+256 |
first_meta_bg dd ? ;+260 |
mkfs_time dd ? ;+264 |
jnl_blocks rd 17 ;+268 |
blocks_count_hi dd ? ;+336 |
r_blocks_count_hi dd ? ;+340 |
free_blocks_count_hi dd ? ;+344 |
min_extra_isize dw ? ;+348 |
want_extra_isize dw ? ;+350 |
flags dd ? ;+352 |
raid_stride dw ? ;+356 |
mmp_interval dw ? ;+358 |
mmp_block dq ? ;+360 |
raid_stripe_width dd ? ;+368 |
log_groups_per_flex db ? ;+372 |
ends |
struct EXT4_EXTENT_HEADER ;заголовок блока экстентов/индексов |
eh_magic dw ? ;в текущей реализации ext4 должно быть 0xF30A |
eh_entries dw ? ;количество экстентов/индексов в блоке |
eh_max dw ? ;max количество (используется при записи) |
eh_depth dw ? ;глубина дерева (0, если это блок экстентов) |
eh_generation dd ? ;??? |
ends |
struct EXT4_EXTENT ;экстент |
ee_block dd ? ;номер ext4 блока |
ee_len dw ? ;длина экстента |
ee_start_hi dw ? ;старшие 16 бит 48-битного адреса (пока не используются в KOS) |
ee_start_lo dd ? ;младшие 32 бита 48-битного адреса |
ends |
struct EXT4_EXTENT_IDX ;индес - указатель на блок с экстентами/индексами |
ei_block dd ? ;номер ext4 блока |
ei_leaf_lo dd ? ;младшие 32 бит 48-битного адреса |
ei_leaf_hi dw ? ;старшие 16 бит 48-битного адреса (пока не используются в KOS) |
ei_unused dw ? ;зарезервировано |
ends |
ext2_test_superblock: |
cmp [fs_type], 0x83 |
jne .no |
mov eax, [PARTITION_START] |
add eax, 2 ;superblock start at 1024b |
call hd_read |
cmp [ebx + EXT2_SB_STRUC.log_block_size], 3 ;0,1,2,3 |
ja .no |
cmp [ebx + EXT2_SB_STRUC.magic], 0xEF53 |
jne .no |
cmp [ebx + EXT2_SB_STRUC.state], 1 ;EXT_VALID_FS=1 |
jne .no |
cmp [ebx + EXT2_SB_STRUC.inodes_per_group], 0 |
je .no |
mov eax, [ebx + EXT2_SB_STRUC.feature_incompat] |
test eax, EXT2_FEATURE_INCOMPAT_FILETYPE |
jz .no |
test eax, not EXT4_FEATURE_INCOMPAT_SUPP |
jnz .no |
; OK, this is correct EXT2 superblock |
clc |
ret |
.no: |
; No, this superblock isn't EXT2 |
stc |
ret |
ext2_setup: |
mov [fs_type], 2 |
push 512 |
call kernel_alloc ; mem for superblock |
mov esi, ebx |
mov edi, eax |
mov ecx, 512/4 |
rep movsd ; copy sb to reserved mem |
mov ebx, eax |
mov [ext2_data.sb], eax |
mov eax, [ebx + EXT2_SB_STRUC.blocks_count] |
sub eax, [ebx + EXT2_SB_STRUC.first_data_block] |
dec eax |
xor edx, edx |
div [ebx + EXT2_SB_STRUC.blocks_per_group] |
inc eax |
mov [ext2_data.groups_count], eax |
mov ecx, [ebx + EXT2_SB_STRUC.log_block_size] |
inc ecx |
mov [ext2_data.log_block_size], ecx ; 1, 2, 3, 4 equ 1kb, 2kb, 4kb, 8kb |
mov eax, 1 |
shl eax, cl |
mov [ext2_data.count_block_in_block], eax |
shl eax, 7 |
mov [ext2_data.count_pointer_in_block], eax |
mov edx, eax ; потом еще квадрат найдем |
shl eax, 2 |
mov [ext2_data.block_size], eax |
push eax eax ; 2 kernel_alloc |
mov eax, edx |
mul edx |
mov [ext2_data.count_pointer_in_block_square], eax |
call kernel_alloc |
mov [ext2_data.ext2_save_block], eax ; and for temp block |
call kernel_alloc |
mov [ext2_data.ext2_temp_block], eax ; and for get_inode proc |
movzx ebp, word [ebx + EXT2_SB_STRUC.inode_size] |
mov ecx, [ebx + EXT2_SB_STRUC.blocks_per_group] |
mov [ext2_data.inode_size], ebp |
mov [ext2_data.blocks_per_group], ecx |
push ebp ebp ebp ;3 kernel_alloc |
call kernel_alloc |
mov [ext2_data.ext2_save_inode], eax |
call kernel_alloc |
mov [ext2_data.ext2_temp_inode], eax |
call kernel_alloc |
mov [ext2_data.root_inode], eax |
mov ebx, eax |
mov eax, EXT2_ROOT_INO |
call ext2_get_inode ; read root inode |
jmp return_from_part_set |
;================================================================== |
;read ext2 block form FS to memory |
;in: eax = i_block (address of block in ext2 terms) |
; ebx = pointer to return memory |
;out: eax - error code (0 = no_error) |
ext2_get_block: |
push ebx ecx |
mov ecx, [ext2_data.log_block_size] |
shl eax, cl |
add eax, [PARTITION_START] |
mov ecx, [ext2_data.count_block_in_block] |
@@: |
call hd_read |
cmp [hd_error], 0 |
jnz .fail |
inc eax |
add ebx, 512 |
loop @B |
xor eax, eax |
@@: |
pop ecx ebx |
ret |
.fail: |
mov eax, ERROR_DEVICE |
jmp @B |
;=================================================================== |
;получает номер блока из extent inode |
;in: ecx = номер блока по порядку |
; ebp = адрес extent header`а |
;out: ecx - адрес очередного блока в случае успеха |
; eax - номер ошибки (если равно 0, то ошибки нет) |
ext4_block_recursive_search: |
cmp word [ebp + EXT4_EXTENT_HEADER.eh_magic], 0xF30A ;EXT4_EXT_MAGIC |
jne .fail |
movzx ebx, [ebp + EXT4_EXTENT_HEADER.eh_entries] |
add ebp, sizeof.EXT4_EXTENT_HEADER |
cmp word [ebp - sizeof.EXT4_EXTENT_HEADER + EXT4_EXTENT_HEADER.eh_depth], 0 |
je .leaf_block ;листовой ли это блок? |
;не листовой блок, а индексный ; eax - ext4_extent_idx |
test ebx, ebx |
jz .fail ;пустой индексный блок -> ошибка |
;цикл по индексам экстентов |
@@: |
cmp ebx, 1 ;у индексов не хранится длина, |
je .end_search_index ;поэтому, если остался последний - то это нужный |
cmp ecx, [ebp + EXT4_EXTENT_IDX.ei_block] |
jb .fail |
cmp ecx, [ebp + sizeof.EXT4_EXTENT_IDX + EXT4_EXTENT_IDX.ei_block] ;блок слeдующего индекса |
jb .end_search_index ;следующий дальше - значит текущий, то что нам нужен |
add ebp, sizeof.EXT4_EXTENT_IDX |
dec ebx |
jmp @B |
.end_search_index: |
;ebp указывает на нужный extent_idx, считываем следующий блок |
mov ebx, [ext2_data.ext2_temp_block] |
mov eax, [ebp + EXT4_EXTENT_IDX.ei_leaf_lo] |
call ext2_get_block |
test eax, eax |
jnz .fail |
mov ebp, ebx |
jmp ext4_block_recursive_search ;рекурсивно прыгаем в начало |
.leaf_block: ;листовой блок ebp - ext4_extent |
;цикл по экстентам |
@@: |
test ebx, ebx |
jz .fail ;ни один узел не подошел - ошибка |
mov edx, [ebp + EXT4_EXTENT.ee_block] |
cmp ecx, edx |
jb .fail ;если меньше, значит он был в предыдущих блоках -> ошибка |
movzx edi, [ebp + EXT4_EXTENT.ee_len] |
add edx, edi |
cmp ecx, edx |
jb .end_search_extent ;нашли нужный блок |
add ebp, sizeof.EXT4_EXTENT |
dec ebx |
jmp @B |
.end_search_extent: |
mov edx, [ebp + EXT4_EXTENT.ee_start_lo] |
sub ecx, [ebp + EXT4_EXTENT.ee_block] ;разница в ext4 блоках |
add ecx, edx |
xor eax, eax |
ret |
.fail: |
mov eax, ERROR_FS_FAIL |
ret |
;=================================================================== |
;получает адрес ext2 блока из inode с определнным номером |
;in: ecx = номер блока в inode (0..) |
; ebp = адрес inode |
;out: ecx = адрес очередного блока |
; eax - error code |
ext2_get_inode_block: |
test [ebp + EXT2_INODE_STRUC.i_flags], EXT2_EXTENTS_FL |
jz @F |
pushad |
add ebp, EXT2_INODE_STRUC.i_block ;ebp - extent_header |
call ext4_block_recursive_search |
mov PUSHAD_ECX, ecx |
mov PUSHAD_EAX, eax |
popad |
ret |
@@: |
cmp ecx, 12 ; 0..11 - direct block address |
jb .get_direct_block |
sub ecx, 12 |
cmp ecx, [ext2_data.count_pointer_in_block] ; 12.. - indirect blocks |
jb .get_indirect_block |
sub ecx, [ext2_data.count_pointer_in_block] |
cmp ecx, [ext2_data.count_pointer_in_block_square] |
jb .get_double_indirect_block |
sub ecx, [ext2_data.count_pointer_in_block_square] |
;triple indirect block |
push edx ebx |
mov eax, [ebx + EXT2_INODE_STRUC.i_block + 14*4] |
mov ebx, [ext2_data.ext2_temp_block] |
call ext2_get_block |
test eax, eax |
jnz .fail |
xor edx, edx |
mov eax, ecx |
div [ext2_data.count_pointer_in_block_square] |
;eax - номер в полученном блоке edx - номер дальше |
mov eax, [ebx + eax*4] |
call ext2_get_block |
test eax, eax |
jnz .fail |
mov eax, edx |
jmp @F |
.get_double_indirect_block: |
push edx ebx |
mov eax, [ebp + EXT2_INODE_STRUC.i_block + 13*4] |
mov ebx, [ext2_data.ext2_temp_block] |
call ext2_get_block |
test eax, eax |
jnz .fail |
mov eax, ecx |
@@: |
xor edx, edx |
div [ext2_data.count_pointer_in_block] |
mov eax, [ebx + eax*4] |
call ext2_get_block |
test eax, eax |
jnz .fail |
mov ecx, [ebx + edx*4] |
.fail: |
pop ebx edx |
ret |
.get_indirect_block: |
push ebx |
mov eax, [ebp + EXT2_INODE_STRUC.i_block + 12*4] |
mov ebx, [ext2_data.ext2_temp_block] |
call ext2_get_block |
test eax, eax |
jnz @F ;если не было ошибки |
mov ecx, [ebx + ecx*4] ;заносим результат |
@@: |
pop ebx |
ret |
.get_direct_block: |
mov ecx, [ebp + EXT2_INODE_STRUC.i_block + ecx*4] |
xor eax, eax |
ret |
;=================================================================== |
;get content inode by num |
;in: eax = inode_num |
; ebx = address of inode content |
;out: eax - error code |
ext2_get_inode: |
pushad |
mov edi, ebx ;сохраним адрес inode |
dec eax |
xor edx, edx |
mov ecx, [ext2_data.sb] |
div [ecx + EXT2_SB_STRUC.inodes_per_group] |
push edx ;locale num in group |
mov edx, 32 |
mul edx ; address block_group in global_desc_table |
; в eax - смещение группы с inode-ом относительно начала глобальной дескрипторной таблицы |
; найдем блок в котором он находится |
div [ext2_data.block_size] |
add eax, [ecx + EXT2_SB_STRUC.first_data_block] |
inc eax |
mov ebx, [ext2_data.ext2_temp_block] |
call ext2_get_block |
test eax, eax |
jnz .fail |
add ebx, edx ; локальный номер в блоке |
mov eax, [ebx + EXT2_BLOCK_GROUP_DESC.inode_table]; номер блока - в терминах ext2 |
mov ecx, [ext2_data.log_block_size] |
shl eax, cl |
add eax, [PARTITION_START] ; а старт раздела - в терминах hdd (512) |
;eax - указывает на таблицу inode-ов на hdd |
mov esi, eax ;сохраним его пока в esi |
; прибавим локальный адрес inode-а |
pop eax ; index |
mov ecx, [ext2_data.inode_size] |
mul ecx ; (index * inode_size) |
mov ebp, 512 |
div ebp ;поделим на размер блока |
add eax, esi ;нашли адрес блока для чтения |
mov ebx, [ext2_data.ext2_temp_block] |
call hd_read |
cmp [hd_error], 0 |
jnz .fail |
mov esi, edx ;добавим "остаток" |
add esi, ebx ;к адресу |
rep movsb ;копируем inode |
xor eax, eax |
.fail: |
mov PUSHAD_EAX, eax |
popad |
ret |
;---------------------------------------------------------------- |
; |
; ext2_HdReadFolder - read disk folder |
; |
; esi points to filename |
; ebx pointer to structure 32-bit number = first wanted block, 0+ |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = blocks read or 0xffffffff folder not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
ext2_HdReadFolder: |
cmp byte [esi], 0 |
jz .root_folder |
push ebx ecx edx |
call ext2_find_lfn ;вернет в ebp адрес inode |
pop edx ecx ebx |
test eax, eax |
jnz .error_ret |
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR |
jz .error_not_found |
jmp @F |
.root_folder: |
mov ebp, [ext2_data.root_inode] |
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR |
jz .error_root |
;придется копировать inode |
push ecx |
mov esi, ebp |
mov edi, [ext2_data.ext2_save_inode] |
mov ecx, [ext2_data.inode_size] |
shr ecx, 2 |
mov ebp, edi |
rep movsd |
pop ecx |
@@: |
cmp [ebp + EXT2_INODE_STRUC.i_size], 0 ;папка пуста |
je .error_empty_dir |
push edx ;адрес результата [edi + 28] |
push 0 ;конец очередного блока папки [edi + 24] |
push ecx ;сколько файлов нужно прочитать [edi + 20] |
push dword [ebx] ;первый "нужный" файл [edi + 16] |
push dword [ebx + 4];флаги [edi + 12] |
push 0 ;[EXT2_read_in_folder] [edi + 8] |
push 0 ;[EXT2_files_in_folder] [edi + 4] |
push 0 ;номер блока по порядку [edi] |
mov edi, edx |
mov ecx, 32/4 |
rep stosd ; fill header zero |
mov edi, esp ; edi - указатель на локальные переменные |
add edx, 32 ; edx = current mem for return |
xor ecx, ecx ; получим номер первого блока |
call ext2_get_inode_block |
test eax, eax |
jnz .error_get_block |
mov eax, ecx |
mov ebx, [ext2_data.ext2_save_block] |
call ext2_get_block ; и считываем блок с hdd |
test eax, eax |
jnz .error_get_block |
mov esi, ebx ; esi = current dir record |
add ebx, [ext2_data.block_size] |
mov [edi + 24], ebx ; запомним конец очередного блока |
mov ecx, [edi + 16] ; ecx = first wanted (flags ommited) |
.find_wanted_start: |
jecxz .find_wanted_end |
.find_wanted_cycle: |
cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used |
jz @F |
inc dword [edi + 4] ; EXT2_files_in_folder |
dec ecx |
@@: |
movzx ebx, [esi + EXT2_DIR_STRUC.rec_len] |
cmp ebx, 12 ; минимальная длина записи |
jb .error_bad_len |
test ebx, 0x3 ; длина записи должна делиться на 4 |
jnz .error_bad_len |
sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode |
add esi, ebx ; к следующей записи |
cmp esi, [edi + 24] ; сравниваем с концом блока |
jb .find_wanted_start |
push .find_wanted_start |
.end_block: ;вылетели из цикла |
cmp [ebp + EXT2_INODE_STRUC.i_size], 0 |
jle .end_dir |
inc dword [edi] ;получаем новый блок |
push ecx |
mov ecx, [edi] |
call ext2_get_inode_block |
test eax, eax |
jnz .error_get_block |
mov eax, ecx |
mov ebx, [ext2_data.ext2_save_block] |
call ext2_get_block |
test eax, eax |
jnz .error_get_block |
pop ecx |
mov esi, ebx |
add ebx, [ext2_data.block_size] |
mov [edi + 24], ebx ;запомним конец блока |
ret ; опять в цикл |
.wanted_end: |
loop .find_wanted_cycle ; ecx 0 => -1 нужно посчитать сколько файлов |
;дошли до первого "нужного" файла |
.find_wanted_end: |
mov ecx, [edi + 20] |
.wanted_start: ; ищем first_wanted+count |
jecxz .wanted_end |
cmp [esi + EXT2_DIR_STRUC.inode], 0 ; if (inode = 0) => not used |
jz .empty_rec |
inc dword [edi + 8] |
inc dword [edi + 4] |
push edi ecx |
mov edi, edx ;обнуляем место под очереное имя файла/папки |
xor eax, eax |
mov ecx, 40 / 4 |
rep stosd |
pop ecx edi |
push esi edi edx |
mov eax, [esi + EXT2_DIR_STRUC.inode] ;получим дочерний inode |
mov ebx, [ext2_data.ext2_temp_inode] |
call ext2_get_inode |
test eax, eax |
jnz .error_read_subinode |
lea edi, [edx + 8] |
mov eax, [ebx + EXT2_INODE_STRUC.i_ctime] ; переведем время в ntfs формат |
xor edx, edx |
add eax, 3054539008 ;(369 * 365 + 89) * 24 * 3600 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
mov eax, [ebx + EXT2_INODE_STRUC.i_atime] |
xor edx, edx |
add eax, 3054539008 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
mov eax, [ebx + EXT2_INODE_STRUC.i_mtime] |
xor edx, edx |
add eax, 3054539008 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
pop edx ; пока достаем только буфер |
test [ebx + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR ; для папки размер |
jnz @F ; не возвращаем |
mov eax, [ebx + EXT2_INODE_STRUC.i_size] ;low size |
stosd |
mov eax, [ebx + EXT2_INODE_STRUC.i_dir_acl] ;high size |
stosd |
xor dword [edx], FS_FT_DIR ;помечаем, что это файл(2 раза xor) |
@@: |
xor dword [edx], FS_FT_DIR ;помечаем, что это файл |
;теперь скопируем имя, сконвертировав из UTF-8 в CP866 |
push ecx ;edi и esi уже сохранены в стеке |
movzx ecx, [esi + EXT2_DIR_STRUC.name_len] |
lea edi, [edx + 40] |
lea esi, [esi + EXT2_DIR_STRUC.name] |
call utf8_to_cp866 |
and byte [edi], 0 |
pop ecx edi esi |
cmp byte [edx + 40], '.' ; в linux файл, начинающийся с точки - скрытый |
jne @F |
or dword [edx], FS_FT_HIDDEN |
@@: |
add edx, 40 + 264 ; go to next record |
dec ecx ; если запись пустая ecx не надо уменьшать |
.empty_rec: |
movzx ebx, [esi + EXT2_DIR_STRUC.rec_len] |
cmp ebx, 12 ; минимальная длина записи |
jb .error_bad_len |
test ebx, 0x3 ; длина записи должна делиться на 4 |
jnz .error_bad_len |
sub [ebp + EXT2_INODE_STRUC.i_size], ebx ;вычитаем напрямую из структуры inode |
add esi, ebx |
cmp esi, [edi + 24] ;дошли ли до конца блока? |
jb .wanted_start |
push .wanted_start ; дошли |
jmp .end_block |
.end_dir: ;конец папки, когда еще не дошли до нужного файла |
mov edx, [edi + 28] ;адрес структуры результата |
mov ebx, [edi + 8] ;EXT2_read_in_folder |
mov ecx, [edi + 4] ;EXT2_files_in_folder |
mov dword [edx], 1 ;version |
mov [edx + 4], ebx |
mov [edx + 8], ecx |
lea esp, [edi + 32] |
xor eax, eax ;зарезервировано: нули в текущей реализации |
lea edi, [edx + 12] |
mov ecx, 20 / 4 |
rep stosd |
ret |
.error_bad_len: |
mov eax, ERROR_FS_FAIL |
.error_read_subinode: |
.error_get_block: |
lea esp, [edi + 32] |
.error_ret: |
or ebx, -1 |
ret |
.error_empty_dir: ;inode папки без блоков |
.error_root: ;root - не папка |
mov eax, ERROR_FS_FAIL |
jmp .error_ret |
.error_not_found: ;файл не найден |
mov eax, ERROR_FILE_NOT_FOUND |
jmp .error_ret |
;============================================ |
;convert UTF-8 string to ASCII-string (codepage 866) |
;in: ecx = length source |
; esi = source |
; edi = buffer |
; destroys: eax,esi,edi |
utf8_to_cp866: |
jecxz .ret |
.start: |
lodsw |
cmp al, 0x80 |
jb .ascii |
xchg al, ah ; big-endian |
cmp ax, 0xd080 |
jz .yo1 |
cmp ax, 0xd191 |
jz .yo2 |
cmp ax, 0xd090 |
jb .unk |
cmp ax, 0xd180 |
jb .rus1 |
cmp ax, 0xd190 |
jb .rus2 |
.unk: |
mov al, '_' |
jmp .doit |
.yo1: |
mov al, 0xf0 ; Ё capital |
jmp .doit |
.yo2: |
mov al, 0xf1 ; ё small |
jmp .doit |
.rus1: |
sub ax, 0xd090 - 0x80 |
jmp .doit |
.rus2: |
sub ax, 0xd18f - 0xEF |
.doit: |
stosb |
sub ecx, 2 |
ja .start |
ret |
.ascii: |
stosb |
dec esi |
dec ecx |
jnz .start |
.ret: |
ret |
;---------------------------------------------------------------- |
; |
; ext2_HdRead - read hard disk |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
;-------------------------------------------------------------- |
ext2_HdRead: |
cmp byte [esi], 0 |
jnz @F |
.this_is_nofile: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
@@: |
push ecx ebx edx |
call ext2_find_lfn |
pop edx ebx ecx |
test eax, eax |
jz @F |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
mov ax, [ebp + EXT2_INODE_STRUC.i_mode] |
and ax, EXT2_S_IFMT ;оставляем только тип inode в ax |
cmp ax, EXT2_S_IFREG |
jne .this_is_nofile |
mov edi, edx ; edi = pointer to return mem |
test ebx, ebx |
jz @F |
mov esi, ebx ; esi = pointer to first_wanted |
mov ebx, [esi+4] |
mov eax, [esi] ; ebx : eax - стартовый номер байта |
;///// сравним хватит ли нам файла или нет |
cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx |
ja .size_great |
jb .size_less |
cmp [ebp + EXT2_INODE_STRUC.i_size], eax |
ja .size_great |
.size_less: |
xor ebx, ebx |
mov eax, ERROR_END_OF_FILE |
ret |
@@: |
xor ebx, ebx |
xor eax, eax |
.size_great: |
add eax, ecx ;add to first_wanted кол-во байт для чтения |
adc ebx, 0 |
cmp [ebp + EXT2_INODE_STRUC.i_dir_acl], ebx |
ja .size_great_great |
jb .size_great_less |
cmp [ebp + EXT2_INODE_STRUC.i_size], eax |
jae .size_great_great |
.size_great_less: |
push 1 ;читаем по границе размера |
mov ecx, [ebp + EXT2_INODE_STRUC.i_size] |
sub ecx, [esi] ;(размер - старт) = сколько читать |
jmp @F |
.size_great_great: |
push 0 ;читаем столько сколько запросили |
@@: |
;здесь мы точно знаем сколько байт читать - ecx |
;edi - return memory |
;esi -> first wanted |
push ecx ;количество считанных байт |
test esi, esi |
jz .zero_start |
;получим кусок из первого блока |
mov edx, [esi+4] |
mov eax, [esi] |
div [ext2_data.block_size] |
push eax ;счетчик блоков ложим в стек |
push ecx |
mov ecx, eax |
call ext2_get_inode_block |
test eax, eax |
jnz .error_at_first_block |
mov ebx, [ext2_data.ext2_save_block] |
mov eax, ecx |
call ext2_get_block |
test eax, eax |
jnz .error_at_first_block |
pop ecx |
add ebx, edx |
neg edx |
add edx, [ext2_data.block_size] ;block_size - стартовый байт = сколько байт 1-го блока |
cmp ecx, edx |
jbe .only_one_block |
mov eax, ecx |
sub eax, edx |
mov ecx, edx |
mov esi, ebx |
rep movsb ;кусок 1-го блока |
jmp .calc_blocks_count |
.zero_start: |
mov eax, ecx |
push 0 ;счетчик блоков ложим в стек |
;теперь в eax кол-во оставшихся байт для чтения |
.calc_blocks_count: |
mov ebx, edi ;чтение блока прям в ->ebx |
xor edx, edx |
div [ext2_data.block_size] ;кол-во байт в последнем блоке (остаток) в edx |
mov edi, eax ;кол-во целых блоков в edi |
@@: |
test edi, edi |
jz .finish_block |
inc dword [esp] |
mov ecx, [esp] |
call ext2_get_inode_block |
test eax, eax |
jnz .error_at_read_cycle |
mov eax, ecx ;а ebx уже забит нужным значением |
call ext2_get_block |
test eax, eax |
jnz .error_at_read_cycle |
add ebx, [ext2_data.block_size] |
dec edi |
jmp @B |
.finish_block: ;в edx - кол-во байт в последнем блоке |
test edx, edx |
jz .end_read |
pop ecx ;счетчик блоков -> ecx |
inc ecx |
call ext2_get_inode_block |
test eax, eax |
jnz .error_at_finish_block |
mov edi, ebx |
mov eax, ecx |
mov ebx, [ext2_data.ext2_save_block] |
call ext2_get_block |
test eax, eax |
jnz .error_at_finish_block |
mov ecx, edx |
mov esi, ebx |
rep movsb ;кусок last блока |
jmp @F |
.end_read: |
pop ecx ;счетчик блоков, который хранился в стеке |
@@: |
pop ebx ;количество считанных байт |
pop eax ; 1 или 0 - достигли ли конца файла |
test eax, eax |
jz @F |
mov eax, ERROR_END_OF_FILE |
ret |
@@: |
xor eax, eax |
ret |
.only_one_block: |
mov esi, ebx |
rep movsb ;кусок last блока |
jmp .end_read |
.error_at_first_block: |
pop edx |
.error_at_read_cycle: |
pop ebx |
.error_at_finish_block: |
pop ecx edx |
or ebx, -1 |
ret |
;---------------------------------------------------------------- |
; in: esi = file path |
; ebx = pointer to dir block |
; out: esi - name without parent or not_changed |
; ebx - dir_rec of inode children |
ext2_test_block_by_name: |
sub esp, 256 ;EXT2_filename |
mov edx, ebx |
add edx, [ext2_data.block_size] ;запомним конец блока |
.start_rec: |
cmp [ebx + EXT2_DIR_STRUC.inode], 0 |
jz .next_rec |
mov edi, esp |
push esi |
movzx ecx, [ebx + EXT2_DIR_STRUC.name_len] |
lea esi, [ebx + EXT2_DIR_STRUC.name] |
call utf8_to_cp866 |
mov ecx, edi |
lea edi, [esp + 4] |
sub ecx, edi ;кол-во байт в получившейся строке |
mov esi, [esp] |
@@: |
jecxz .test_find |
dec ecx |
lodsb |
call char_toupper |
mov ah, [edi] |
inc edi |
xchg al, ah |
call char_toupper |
cmp al, ah |
je @B |
@@: ;не подошло |
pop esi |
.next_rec: |
movzx eax, [ebx + EXT2_DIR_STRUC.rec_len] |
add ebx, eax ;к след. записи |
cmp ebx, edx ;проверим конец ли |
jb .start_rec |
add esp, 256 |
ret |
.test_find: |
cmp byte [esi], 0 |
je .ret ;нашли конец |
cmp byte [esi], '/' |
jne @B |
inc esi |
.ret: |
add esp, 256 + 4 |
ret |
;======================== |
;Ищет inode по строке пути |
;in: esi = name |
;out: eax - error code |
; ebp = inode |
; dl - первый байт из имени файла/папки |
ext2_find_lfn: |
mov ebp, [ext2_data.root_inode] |
cmp [ebp + EXT2_INODE_STRUC.i_blocks], 0 |
je .error_empty_root |
.next_path_part: |
push [ebp + EXT2_INODE_STRUC.i_blocks] |
xor ecx, ecx |
.folder_block_cycle: |
push ecx |
call ext2_get_inode_block |
test eax, eax |
jnz .error_get_inode_block |
mov eax, ecx |
mov ebx, [ext2_data.ext2_save_block] ;ebx = cur dir record |
call ext2_get_block |
test eax, eax |
jnz .error_get_block |
push esi |
call ext2_test_block_by_name |
pop edi ecx |
cmp edi, esi ;нашли имя? |
je .next_folder_block ;не нашли -> к след. блоку |
cmp byte [esi], 0 ;дошли до "конца" пути -> возваращаемся |
jz .get_inode_ret |
cmp [ebx + EXT2_DIR_STRUC.file_type], EXT2_FT_DIR ;нашли, но это не папка |
jne .not_found |
mov eax, [ebx + EXT2_DIR_STRUC.inode] |
mov ebx, [ext2_data.ext2_save_inode] ;все же папка. |
call ext2_get_inode |
test eax, eax |
jnz .error_get_inode |
pop ecx ;в стеке лежит кол-во блоков |
mov ebp, ebx |
jmp .next_path_part |
.next_folder_block: |
;к следующему блоку в текущей папке |
pop eax ;счетчик блоков |
sub eax, [ext2_data.count_block_in_block] |
jle .not_found |
push eax |
inc ecx |
jmp .folder_block_cycle |
.not_found: |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.get_inode_ret: |
pop ecx ;в стеке лежит кол-во блоков |
mov dl, [ebx + EXT2_DIR_STRUC.name] ;в dl - первый символ () |
mov eax, [ebx + EXT2_DIR_STRUC.inode] |
mov ebx, [ext2_data.ext2_save_inode] |
call ext2_get_inode |
mov ebp, ebx |
xor eax, eax |
ret |
.error_get_inode_block: |
.error_get_block: |
pop ecx |
.error_get_inode: |
pop ebx |
.error_empty_root: |
mov eax, ERROR_FS_FAIL |
ret |
;---------------------------------------------------------------- |
;ext2_HdGetFileInfo - read file info from block device |
; |
;in: esi points to filename |
; edx mem location to return data |
;-------------------------------------------------------------- |
ext2_HdGetFileInfo: |
xchg bx, bx |
cmp byte [esi], 0 |
jz .is_root |
push edx |
call ext2_find_lfn |
mov ebx, edx |
pop edx |
test eax, eax |
jz @F |
ret |
.is_root: |
xor ebx, ebx ;root не может быть скрытым |
mov ebp, [ext2_data.root_inode] |
@@: |
xor eax, eax |
mov edi, edx |
mov ecx, 40/4 |
rep stosd ; fill zero |
cmp bl, '.' |
jne @F |
or dword [edx], FS_FT_HIDDEN |
@@: |
test [ebp + EXT2_INODE_STRUC.i_mode], EXT2_S_IFDIR |
jnz @F |
mov eax, [ebp + EXT2_INODE_STRUC.i_size] ;low size |
mov ebx, [ebp + EXT2_INODE_STRUC.i_dir_acl] ;high size |
mov dword [edx+32], eax |
mov dword [edx+36], ebx |
xor dword [edx], FS_FT_DIR |
@@: |
xor dword [edx], FS_FT_DIR |
lea edi, [edx + 8] |
mov eax, [ebp + EXT2_INODE_STRUC.i_ctime] |
xor edx, edx |
add eax, 3054539008 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
mov eax, [ebp + EXT2_INODE_STRUC.i_atime] |
xor edx, edx |
add eax, 3054539008 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
mov eax, [ebp + EXT2_INODE_STRUC.i_mtime] |
xor edx, edx |
add eax, 3054539008 |
adc edx, 2 |
call ntfs_datetime_to_bdfe.sec |
xor eax, eax |
ret |
ext2_HdRewrite: |
ext2_HdWrite: |
ext2_HdSetFileEnd: |
ext2_HdSetFileInfo: |
ext2_HdDelete: |
ext2_HdCreateFolder: |
xor ebx, ebx |
mov eax, ERROR_UNSUPPORTED_FS |
ret |
/kernel/branches/net/fs/fat12.inc |
---|
0,0 → 1,2275 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; FAT12.INC ;; |
;; (C) 2005 Mario79, License: GPL ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
n_sector dd 0 ; temporary save for sector value |
flp_status dd 0 |
clust_tmp_flp dd 0 ; used by analyze_directory and analyze_directory_to_write |
path_pointer_flp dd 0 |
pointer_file_name_flp dd 0 |
save_root_flag db 0 |
save_flag db 0 |
root_read db 0 ; 0-necessary to load root, 1-not to load root |
flp_fat db 0 ; 0-necessary to load fat, 1-not to load fat |
flp_number db 0 ; 1- Floppy A, 2-Floppy B |
old_track db 0 ; old value track |
flp_label rb 15 ; Label and ID of inserted floppy disk |
reserve_flp: |
cli |
cmp [flp_status], 0 |
je reserve_flp_ok |
sti |
call change_task |
jmp reserve_flp |
reserve_flp_ok: |
push eax |
mov eax, [CURRENT_TASK] |
shl eax, 5 |
mov eax, [eax+CURRENT_TASK+TASKDATA.pid] |
mov [flp_status], eax |
pop eax |
sti |
ret |
floppy_fileread: |
;---------------------------------------------------------------- |
; |
; fileread - sys floppy |
; |
; eax points to filename 11 chars - for root directory |
; ebx first wanted block ; 1+ ; if 0 then set to 1 |
; ecx number of blocks to read ; 1+ ; if 0 then set to 1 |
; edx mem location to return data |
; esi length of filename 12*X |
; edi pointer to path /fd/1/...... - for all files in nested directories |
; |
; ret ebx = size or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; 10 = access denied |
;-------------------------------------------------------------- |
mov [save_flag], 0 |
mov [path_pointer_flp], edi |
test esi, esi ; return ramdisk root |
jnz fr_noroot_1 |
cmp ebx, 224/16 |
jbe fr_do_1 |
mov eax, 5 |
xor ebx, ebx |
mov [flp_status], ebx |
ret |
fr_do_1: |
push ebx ecx edx |
call read_flp_root |
pop edx ecx ebx |
cmp [FDC_Status], 0 |
jne fdc_status_error_1 |
mov edi, edx |
dec ebx |
shl ebx, 9 |
mov esi, FLOPPY_BUFF |
add esi, ebx |
shl ecx, 9 |
cld |
rep movsb |
xor eax, eax |
xor ebx, ebx |
; mov eax,0 ; ok read |
; mov ebx,0 |
mov [flp_status], eax |
ret |
fdc_status_error_1: |
xor eax, eax |
mov [flp_status], eax |
mov eax, 10 |
or ebx, -1 |
ret |
fr_noroot_1: |
sub esp, 32 |
call expand_filename |
frfloppy_1: |
test ebx, ebx |
jnz frfl5_1 |
mov ebx, 1 |
frfl5_1: |
test ecx, ecx |
jnz frfl6_1 |
mov ecx, 1 |
frfl6_1: |
dec ebx |
push eax |
push eax ebx ecx edx esi edi |
call read_flp_fat |
cmp [FDC_Status], 0 |
jne fdc_status_error_3_1 |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 1; Ñòîðîíà |
mov [FDD_Sector], 2; Ñåêòîð |
call SeekTrack |
mov dh, 14 |
l.20_1: |
call ReadSectWithRetr |
cmp [FDC_Status], 0 |
jne fdc_status_error_3_1 |
mov dl, 16 |
mov edi, FDD_BUFF |
inc [FDD_Sector] |
l.21_1: |
mov esi, eax ;Name of file we want |
mov ecx, 11 |
cld |
rep cmpsb ;Found the file? |
je fifound_1 ;Yes |
add ecx, 21 |
add edi, ecx ;Advance to next entry |
dec dl |
test dl, dl |
jnz l.21_1 |
dec dh |
test dh, dh |
jnz l.20_1 |
fdc_status_error_3: |
mov eax, 5 ; file not found ? |
or ebx, -1 |
add esp, 32+28 |
mov [flp_status], 0 |
ret |
fdc_status_error_3_2: |
cmp [FDC_Status], 0 |
je fdc_status_error_3 |
fdc_status_error_3_1: |
add esp, 32+28 |
jmp fdc_status_error_1 |
fifound_1: |
mov eax, [path_pointer_flp] |
cmp [eax+36], byte 0 |
je fifound_2 |
add edi, 0xf |
mov eax, [edi] |
and eax, 65535 |
mov ebx, [path_pointer_flp] |
add ebx, 36 |
call get_cluster_of_a_path_flp |
jc fdc_status_error_3_2 |
mov ebx, [ebx-11+28] ;file size |
mov [esp+20], ebx |
mov [esp+24], ebx |
jmp fifound_3 |
fifound_2: |
mov ebx, [edi-11+28] ;file size |
mov [esp+20], ebx |
mov [esp+24], ebx |
add edi, 0xf |
mov eax, [edi] |
fifound_3: |
and eax, 65535 |
mov [n_sector], eax ;eax=cluster |
frnew_1: |
add eax, 31 ;bootsector+2*fat+filenames |
cmp [esp+16], dword 0; wanted cluster ? |
jne frfl7_1 |
call read_chs_sector |
cmp [FDC_Status], 0 |
jne fdc_status_error_5 |
mov edi, [esp+8] |
call give_back_application_data_1 |
add [esp+8], dword 512 |
dec dword [esp+12] ; last wanted cluster ? |
cmp [esp+12], dword 0 |
je frnoread_1 |
jmp frfl8_1 |
frfl7_1: |
dec dword [esp+16] |
frfl8_1: |
mov edi, [n_sector] |
shl edi, 1 ;find next cluster from FAT |
add edi, FLOPPY_FAT |
mov eax, [edi] |
and eax, 4095 |
mov edi, eax |
mov [n_sector], edi |
cmp edi, 4095 ;eof - cluster |
jz frnoread2_1 |
cmp [esp+24], dword 512;eof - size |
jb frnoread_1 |
sub [esp+24], dword 512 |
jmp frnew_1 |
read_chs_sector: |
call calculate_chs |
call ReadSectWithRetr |
ret |
frnoread2_1: |
cmp [esp+16], dword 0; eof without read ? |
je frnoread_1 |
mov [fdc_irq_func], fdc_null |
pop edi esi edx ecx |
add esp, 4 |
pop ebx; ebx <- eax : size of file |
add esp, 36 |
mov eax, 6; end of file |
mov [flp_status], 0 |
ret |
frnoread_1: |
pop edi esi edx ecx |
add esp, 4 |
pop ebx; ebx <- eax : size of file |
add esp, 36 |
xor eax, eax |
mov [flp_status], eax |
ret |
fdc_status_error_5: |
pop edi esi edx ecx |
add esp, 4 |
pop ebx; ebx <- eax : size of file |
add esp, 36 |
jmp fdc_status_error_1 |
read_flp_root: |
pusha |
call check_label |
cmp [FDC_Status], 0 |
jne unnecessary_root_read |
cmp [root_read], 1 |
je unnecessary_root_read |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 1; Ñòîðîíà |
mov [FDD_Sector], 2; Ñåêòîð |
mov edi, FLOPPY_BUFF |
call SeekTrack |
read_flp_root_1: |
call ReadSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_root_read |
push edi |
call give_back_application_data_1 |
pop edi |
add edi, 512 |
inc [FDD_Sector] |
cmp [FDD_Sector], 16 |
jne read_flp_root_1 |
mov [root_read], 1 |
unnecessary_root_read: |
popa |
ret |
read_flp_fat: |
pusha |
call check_label |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat |
cmp [flp_fat], 1 |
je unnecessary_flp_fat |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 0; Ñòîðîíà |
mov [FDD_Sector], 2; Ñåêòîð |
mov edi, FLOPPY_BUFF |
call SeekTrack |
read_flp_fat_1: |
call ReadSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat |
push edi |
call give_back_application_data_1 |
pop edi |
add edi, 512 |
inc [FDD_Sector] |
cmp [FDD_Sector], 19 |
jne read_flp_fat_1 |
mov [FDD_Sector], 1 |
mov [FDD_Head], 1 |
call ReadSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat |
call give_back_application_data_1 |
call calculatefatchain_flp |
mov [root_read], 0 |
mov [flp_fat], 1 |
unnecessary_flp_fat: |
popa |
ret |
calculatefatchain_flp: |
pushad |
mov esi, FLOPPY_BUFF |
mov edi, FLOPPY_FAT |
fcnew_1: |
mov eax, dword [esi] |
mov ebx, dword [esi+4] |
mov ecx, dword [esi+8] |
mov edx, ecx |
shr edx, 4;8 ok |
shr dx, 4;7 ok |
xor ch, ch |
shld ecx, ebx, 20;6 ok |
shr cx, 4;5 ok |
shld ebx, eax, 12 |
and ebx, 0x0fffffff;4 ok |
shr bx, 4;3 ok |
shl eax, 4 |
and eax, 0x0fffffff;2 ok |
shr ax, 4;1 ok |
mov dword [edi], eax |
add edi, 4 |
mov dword [edi], ebx |
add edi, 4 |
mov dword [edi], ecx |
add edi, 4 |
mov dword [edi], edx |
add edi, 4 |
add esi, 12 |
cmp edi, FLOPPY_FAT+2856*2;2849 clusters |
jnz fcnew_1 |
popad |
ret |
check_label: |
pushad |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 0; Ñòîðîíà |
mov [FDD_Sector], 1; Ñåêòîð |
call SetUserInterrupts |
call FDDMotorON |
call RecalibrateFDD |
cmp [FDC_Status], 0 |
jne fdc_status_error |
call SeekTrack |
cmp [FDC_Status], 0 |
jne fdc_status_error |
call ReadSectWithRetr |
cmp [FDC_Status], 0 |
jne fdc_status_error |
mov esi, flp_label |
mov edi, FDD_BUFF+39 |
mov ecx, 15 |
cld |
rep cmpsb |
je same_label |
mov [root_read], 0 |
mov [flp_fat], 0 |
same_label: |
mov esi, FDD_BUFF+39 |
mov edi, flp_label |
mov ecx, 15 |
cld |
rep movsb |
popad |
ret |
fdc_status_error: |
popad |
ret |
save_flp_root: |
pusha |
call check_label |
cmp [FDC_Status], 0 |
jne unnecessary_root_save |
cmp [root_read], 0 |
je unnecessary_root_save |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 1; Ñòîðîíà |
mov [FDD_Sector], 2; Ñåêòîð |
mov esi, FLOPPY_BUFF |
call SeekTrack |
save_flp_root_1: |
push esi |
call take_data_from_application_1 |
pop esi |
add esi, 512 |
call WriteSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_root_save |
inc [FDD_Sector] |
cmp [FDD_Sector], 16 |
jne save_flp_root_1 |
unnecessary_root_save: |
mov [fdc_irq_func], fdc_null |
popa |
ret |
save_flp_fat: |
pusha |
call check_label |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat_save |
cmp [flp_fat], 0 |
je unnecessary_flp_fat_save |
call restorefatchain_flp |
mov [FDD_Track], 0; Öèëèíäð |
mov [FDD_Head], 0; Ñòîðîíà |
mov [FDD_Sector], 2; Ñåêòîð |
mov esi, FLOPPY_BUFF |
call SeekTrack |
save_flp_fat_1: |
push esi |
call take_data_from_application_1 |
pop esi |
add esi, 512 |
call WriteSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat_save |
inc [FDD_Sector] |
cmp [FDD_Sector], 19 |
jne save_flp_fat_1 |
mov [FDD_Sector], 1 |
mov [FDD_Head], 1 |
call take_data_from_application_1 |
call WriteSectWithRetr |
cmp [FDC_Status], 0 |
jne unnecessary_flp_fat_save |
mov [root_read], 0 |
unnecessary_flp_fat_save: |
mov [fdc_irq_func], fdc_null |
popa |
ret |
restorefatchain_flp: ; restore fat chain |
pushad |
mov esi, FLOPPY_FAT |
mov edi, FLOPPY_BUFF |
fcnew2_1: |
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 |
add edi, 4 |
mov word [edi], bx |
add edi, 2 |
add esi, 8 |
cmp edi, FLOPPY_BUFF+0x1200;4274 bytes - all used FAT |
jb fcnew2_1 |
mov esi, FLOPPY_BUFF ; duplicate fat chain |
mov edi, FLOPPY_BUFF+0x1200 |
mov ecx, 0x1200/4 |
cld |
rep movsd |
popad |
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 |
xor edx, edx |
mov ebx, 2 |
div ebx |
mov [FDD_Track], al |
mov [FDD_Head], 0 |
test edx, edx |
jz no_head_2 |
inc [FDD_Head] |
no_head_2: |
mov dl, [old_track] |
cmp dl, [FDD_Track] |
je no_seek_track_1 |
call SeekTrack |
no_seek_track_1: |
ret |
get_cluster_of_a_path_flp: |
;--------------------------------------------------------- |
; input : EBX = pointer to a path string |
; (example: the path "/files/data/document" become |
; "files......data.......document...0" |
; '.' = space char |
; '0' = char(0) (ASCII=0) !!! ) |
; output : if (CARRY=1) -> ERROR in the PATH |
; if (CARRY=0) -> EAX=cluster |
;--------------------------------------------------------- |
push edx |
mov edx, ebx |
search_end_of_path_flp: |
cmp [save_flag], 0 |
jne search_end_of_path_flp_1 |
cmp byte [edx], 0 |
je found_end_of_path_flp |
jmp search_end_of_path_flp_2 |
search_end_of_path_flp_1: |
cmp byte [edx+12], 0 |
je found_end_of_path_flp |
search_end_of_path_flp_2: |
inc edx; '/' |
call analyze_directory_flp |
jc directory_not_found_flp |
mov eax, [ebx+20-2] ; read the HIGH 16bit cluster field |
mov ax, [ebx+26] ; read the LOW 16bit cluster field |
and eax, 0xfff ;[fatMASK] |
add edx, 11 ; 8+3 (name+extension) |
jmp search_end_of_path_flp |
found_end_of_path_flp: |
inc edx |
mov [pointer_file_name_flp], edx |
pop edx |
clc ; no errors |
ret |
directory_not_found_flp: |
pop edx |
stc ; errors occour |
ret |
analyze_directory_flp: |
;-------------------------------- |
; input : EAX = first cluster of the directory |
; EBX = pointer to filename |
; output : IF CARRY=0 EAX = sector where th file is found |
; EBX = pointer in buffer |
; [buffer .. buffer+511] |
; ECX,EDX,EDI,EDI not changed |
; IF CARRY=1 |
;-------------------------------- |
push ebx;[esp+16] |
push ecx |
push edx |
push esi |
push edi |
adr56_flp: |
mov [clust_tmp_flp], eax |
add eax, 31 |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jne not_found_file_analyze_flp |
mov ecx, 512/32 |
mov ebx, FDD_BUFF |
adr1_analyze_flp: |
mov esi, edx;[esp+16] |
mov edi, ebx |
cld |
push ecx |
mov ecx, 11 |
rep cmpsb |
pop ecx |
je found_file_analyze_flp |
add ebx, 32 |
loop adr1_analyze_flp |
mov eax, [clust_tmp_flp] |
shl eax, 1 ;find next cluster from FAT |
add eax, FLOPPY_FAT |
mov eax, [eax] |
and eax, 4095 |
cmp eax, 0x0ff8 |
jb adr56_flp |
not_found_file_analyze_flp: |
pop edi |
pop esi |
pop edx |
pop ecx |
add esp, 4 |
stc ;file not found |
ret |
found_file_analyze_flp: |
pop edi |
pop esi |
pop edx |
pop ecx |
add esp, 4 |
clc ;file found |
ret |
; \begin{diamond} |
fat_find_lfn: |
; in: esi->name |
; [esp+4] = next |
; [esp+8] = first |
; [esp+C]... - possibly parameters for first and next |
; out: CF=1 - file not found, eax=error code |
; else CF=0, esi->next name component, edi->direntry |
pusha |
lea eax, [esp+0Ch+20h] |
call dword [eax-4] |
jc .reterr |
sub esp, 262*2 ; reserve place for LFN |
push 0 ; for fat_get_name: read ASCII name |
.l1: |
lea ebp, [esp+4] |
call fat_get_name |
jc .l2 |
call fat_compare_name |
jz .found |
.l2: |
mov ebp, [esp+8+262*2+4] |
lea eax, [esp+0Ch+20h+262*2+4] |
call dword [eax-8] |
jnc .l1 |
add esp, 262*2+4 |
.reterr: |
mov [esp+28], eax |
stc |
popa |
ret |
.found: |
add esp, 262*2+4 |
mov ebp, [esp+8] |
; if this is LFN entry, advance to true entry |
cmp byte [edi+11], 0xF |
jnz @f |
lea eax, [esp+0Ch+20h] |
call dword [eax-8] |
jc .reterr |
@@: |
add esp, 8 ; CF=0 |
push esi |
push edi |
popa |
ret |
uglobal |
; this is for delete support |
fd_prev_sector dd ? |
fd_prev_prev_sector dd ? |
endg |
flp_root_next: |
cmp edi, OS_BASE+0xD200-0x20 |
jae @f |
add edi, 0x20 |
ret ; CF=0 |
@@: |
; read next sector |
inc dword [eax] |
cmp dword [eax], 14 |
jae flp_root_first.readerr |
push [fd_prev_sector] |
pop [fd_prev_prev_sector] |
push eax |
mov eax, [eax] |
add eax, 19-1 |
mov [fd_prev_sector], eax |
pop eax |
flp_root_first: |
mov eax, [eax] |
pusha |
add eax, 19 |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .readerr |
mov edi, FDD_BUFF |
ret ; CF=0 |
.readerr: |
stc |
ret |
flp_rootmem_first: |
mov edi, FLOPPY_BUFF |
clc |
ret |
flp_rootmem_next: |
add edi, 0x20 |
cmp edi, FLOPPY_BUFF+14*0x200 |
cmc |
flp_rootmem_next_write: |
flp_rootmem_begin_write: |
flp_rootmem_end_write: |
ret |
flp_rootmem_extend_dir: |
stc |
ret |
flp_notroot_next: |
cmp edi, OS_BASE+0xD200-0x20 |
jae flp_notroot_next_sector |
add edi, 0x20 |
ret ; CF=0 |
flp_notroot_next_sector: |
push ecx |
mov ecx, [eax] |
push [fd_prev_sector] |
pop [fd_prev_prev_sector] |
add ecx, 31 |
mov [fd_prev_sector], ecx |
mov ecx, [(ecx-31)*2+FLOPPY_FAT] |
and ecx, 0xFFF |
cmp ecx, 2849 |
jae flp_notroot_first.err2 |
mov [eax], ecx |
pop ecx |
flp_notroot_first: |
mov eax, [eax] |
cmp eax, 2 |
jb .err |
cmp eax, 2849 |
jae .err |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov edi, FDD_BUFF |
cmp [FDC_Status], 0 |
jnz .err |
ret ; CF=0 |
.err2: |
pop ecx |
.err: |
stc |
ret |
flp_notroot_begin_write: |
pusha |
mov eax, [eax] |
add eax, 31 |
call read_chs_sector |
popa |
ret |
flp_notroot_end_write: |
pusha |
mov eax, [eax] |
add eax, 31 |
call save_chs_sector |
popa |
ret |
flp_notroot_next_write: |
cmp edi, OS_BASE+0xD200 |
jae @f |
ret |
@@: |
call flp_notroot_end_write |
jmp flp_notroot_next_sector |
flp_notroot_extend_dir: |
; find free cluster in FAT |
pusha |
xor eax, eax |
mov edi, FLOPPY_FAT |
mov ecx, 2849 |
repnz scasw |
jnz .notfound |
mov word [edi-2], 0xFFF ; mark as last cluster |
sub edi, FLOPPY_FAT |
shr edi, 1 |
dec edi |
mov eax, [esp+28] |
mov ecx, [eax] |
mov [FLOPPY_FAT+ecx*2], di |
mov [eax], edi |
xor eax, eax |
mov edi, FDD_BUFF |
mov ecx, 128 |
rep stosd |
popa |
call flp_notroot_end_write |
mov edi, FDD_BUFF |
clc |
ret |
.notfound: |
popa |
stc |
ret |
fd_find_lfn: |
; in: esi+ebp -> name |
; out: CF=1 - file not found |
; else CF=0 and edi->direntry, eax=directory cluster (0 for root) |
push esi edi |
push 0 |
push flp_root_first |
push flp_root_next |
.loop: |
call fat_find_lfn |
jc .notfound |
cmp byte [esi], 0 |
jz .found |
.continue: |
test byte [edi+11], 10h |
jz .notfound |
movzx eax, word [edi+26] ; cluster |
mov [esp+8], eax |
mov dword [esp+4], flp_notroot_first |
mov dword [esp], flp_notroot_next |
jmp .loop |
.notfound: |
add esp, 12 |
pop edi esi |
stc |
ret |
.found: |
test ebp, ebp |
jz @f |
mov esi, ebp |
xor ebp, ebp |
jmp .continue |
@@: |
mov eax, [esp+8] |
add eax, 31 |
cmp dword [esp], flp_root_next |
jnz @f |
add eax, -31+19 |
@@: |
add esp, 16 ; CF=0 |
pop esi |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyRead - LFN variant for reading floppy |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_FloppyRead: |
call read_flp_fat |
cmp byte [esi], 0 |
jnz @f |
or ebx, -1 |
mov eax, 10 ; access denied |
ret |
@@: |
push edi |
call fd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, 5 ; file not found |
ret |
.found: |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6 ; EOF |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+28] |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 ; EOF |
@@: |
movzx edi, word [edi+26] |
.new: |
jecxz .done |
test edi, edi |
jz .eof |
cmp edi, 0xFF8 |
jae .eof |
sub ebx, 512 |
jae .skip |
lea eax, [edi+31] |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .err |
lea eax, [FDD_BUFF+ebx+512] |
neg ebx |
push ecx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
mov ebx, edx |
call memmove |
add edx, ecx |
sub [esp], ecx |
pop ecx |
xor ebx, ebx |
.skip: |
movzx edi, word [edi*2+FLOPPY_FAT] |
jmp .new |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx ecx |
jmp .reteof |
.err: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
mov al, 11 |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyReadFolder - LFN variant for reading floppy folders |
; |
; esi points to filename |
; ebx pointer to structure: 32-bit number = first wanted block, 0+ |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = blocks read or 0xffffffff folder not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_FloppyReadFolder: |
call read_flp_fat |
push edi |
cmp byte [esi], 0 |
jz .root |
call fd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read files |
jnz .found_dir |
pop edi |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
movzx eax, word [edi+26] |
add eax, 31 |
push 0 |
jmp .doit |
.root: |
mov eax, 19 |
push 14 |
.doit: |
push ecx ebp |
sub esp, 262*2 ; reserve space for LFN |
mov ebp, esp |
push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names |
mov ebx, [ebx] |
; init header |
push eax ecx |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
pop ecx eax |
mov byte [edx], 1 ; version |
mov esi, edi ; esi points to BDFE |
.main_loop: |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .error |
mov edi, FDD_BUFF |
push eax |
.l1: |
call fat_get_name |
jc .l2 |
cmp byte [edi+11], 0xF |
jnz .do_bdfe |
add edi, 0x20 |
cmp edi, OS_BASE+0xD200 |
jb .do_bdfe |
pop eax |
inc eax |
dec byte [esp+262*2+12] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+FLOPPY_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+12], 0 |
@@: |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .error |
mov edi, FDD_BUFF |
push eax |
.do_bdfe: |
inc dword [edx+8] ; new file found |
dec ebx |
jns .l2 |
dec ecx |
js .l2 |
inc dword [edx+4] ; new file block copied |
call fat_entry_to_bdfe |
.l2: |
add edi, 0x20 |
cmp edi, OS_BASE+0xD200 |
jb .l1 |
pop eax |
inc eax |
dec byte [esp+262*2+12] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+FLOPPY_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+12], 0 |
@@: |
jmp .main_loop |
.error: |
add esp, 262*2+4 |
pop ebp ecx edi edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.done: |
add esp, 262*2+4 |
pop ebp |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
pop ecx edi edi |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyRewrite - LFN variant for writing sys floppy |
; |
; esi points to filename |
; ebx ignored (reserved) |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = number of written bytes |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
@@: |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
fsfrfe2: |
popad |
fsfrfe: |
mov eax, 11 |
xor ebx, ebx |
ret |
fs_FloppyCreateFolder: |
mov al, 1 |
jmp fs_FloppyRewrite.common |
fs_FloppyRewrite: |
xor eax, eax |
.common: |
cmp byte [esi], 0 |
jz @b |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz fsfrfe |
pushad |
xor edi, edi |
push esi |
test ebp, ebp |
jz @f |
mov esi, ebp |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea edi, [esi-1] |
jmp @b |
@@: |
pop esi |
test edi, edi |
jnz .noroot |
test ebp, ebp |
jnz .hasebp |
call read_flp_root |
cmp [FDC_Status], 0 |
jnz fsfrfe2 |
push flp_rootmem_extend_dir |
push flp_rootmem_end_write |
push flp_rootmem_next_write |
push flp_rootmem_begin_write |
xor ebp, ebp |
push ebp |
push flp_rootmem_first |
push flp_rootmem_next |
jmp .common1 |
.hasebp: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [ebp], 0 |
jz .ret1 |
push ebp |
xor ebp, ebp |
call fd_find_lfn |
pop esi |
jc .notfound0 |
jmp .common0 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edi+1], 0 |
jz .ret1 |
; check existence |
mov byte [edi], 0 |
push edi |
call fd_find_lfn |
pop esi |
mov byte [esi], '/' |
jnc @f |
.notfound0: |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
popad |
xor ebx, ebx |
ret |
@@: |
inc esi |
.common0: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
movzx ebp, word [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
cmp ebp, 2 |
jb .ret1 |
cmp ebp, 2849 |
jae .ret1 |
push flp_notroot_extend_dir |
push flp_notroot_end_write |
push flp_notroot_next_write |
push flp_notroot_begin_write |
push ebp |
push flp_notroot_first |
push flp_notroot_next |
.common1: |
call fat_find_lfn |
jc .notfound |
; found |
test byte [edi+11], 10h |
jz .exists_file |
; found directory; if we are creating directory, return OK, |
; if we are creating file, say "access denied" |
add esp, 28 |
popad |
test al, al |
mov eax, ERROR_ACCESS_DENIED |
jz @f |
mov al, 0 |
@@: |
xor ebx, ebx |
ret |
.exists_file: |
; found file; if we are creating directory, return "access denied", |
; if we are creating file, delete existing file and continue |
cmp byte [esp+28+28], 0 |
jz @f |
add esp, 28 |
popad |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
@@: |
; delete FAT chain |
push edi |
xor eax, eax |
mov dword [edi+28], eax ; zero size |
xchg ax, word [edi+26] ; start cluster |
test eax, eax |
jz .done1 |
@@: |
cmp eax, 0xFF8 |
jae .done1 |
lea edi, [FLOPPY_FAT + eax*2] ; position in FAT |
xor eax, eax |
xchg ax, [edi] |
jmp @b |
.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 |
jmp .doit |
.notfound: |
; file is not found; generate short name |
call fat_name_is_legal |
jc @f |
add esp, 28 |
popad |
mov eax, ERROR_FILE_NOT_FOUND |
xor ebx, ebx |
ret |
@@: |
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 [eax], ebp |
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 |
jmp .found |
.short_name_found: |
pop ecx edi esi |
call fat_next_short_name |
jnc .test_short_name_loop |
.disk_full: |
add esp, 12+28 |
popa |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.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 |
push 1 |
pop eax ; 1 entry |
jnz .notilde |
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total |
xor eax, eax |
@@: |
cmp byte [esi], 0 |
jz @f |
inc esi |
inc eax |
jmp @b |
@@: |
sub esi, eax |
add eax, 12+13 |
mov ecx, 13 |
push edx |
cdq |
div ecx |
pop edx |
.notilde: |
push -1 |
push -1 |
; find <eax> successive entries in directory |
xor ecx, ecx |
push eax |
lea eax, [esp+12+8+12+8] |
mov [eax], ebp |
call dword [eax-4] |
pop eax |
jnc .scan_dir |
.fsfrfe3: |
add esp, 8+8+12+28 |
popad |
mov eax, 11 |
xor ebx, ebx |
ret |
.scan_dir: |
cmp byte [edi], 0 |
jz .free |
cmp byte [edi], 0xE5 |
jz .free |
xor ecx, ecx |
.scan_cont: |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax-8] |
pop eax |
jnc .scan_dir |
cmp [FDC_Status], 0 |
jnz .fsfrfe3 |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax+16] ; extend directory |
pop eax |
jnc .scan_dir |
add esp, 8+8+12+28 |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.free: |
test ecx, ecx |
jnz @f |
mov [esp], edi |
mov ecx, [esp+8+8+12+8] |
mov [esp+4], ecx |
xor ecx, ecx |
@@: |
inc ecx |
cmp ecx, eax |
jb .scan_cont |
; found! |
; calculate name checksum |
push esi ecx |
mov esi, [esp+8+8] |
mov ecx, 11 |
xor eax, eax |
@@: |
ror al, 1 |
add al, [esi] |
inc esi |
loop @b |
pop ecx esi |
pop edi |
pop dword [esp+8+12+8] |
; edi points to first entry in free chunk |
dec ecx |
jz .nolfn |
push esi |
push eax |
lea eax, [esp+8+8+12+8] |
call dword [eax+4] ; begin write |
mov al, 40h |
.writelfn: |
or al, cl |
mov esi, [esp+4] |
push ecx |
dec ecx |
imul ecx, 13 |
add esi, ecx |
stosb |
mov cl, 5 |
call fs_RamdiskRewrite.read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call fs_RamdiskRewrite.read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call fs_RamdiskRewrite.read_symbols |
pop ecx |
lea eax, [esp+8+8+12+8] |
call dword [eax+8] ; next write |
xor eax, eax |
loop .writelfn |
pop eax |
pop esi |
; lea eax, [esp+8+12+8] |
; call dword [eax+12] ; end write |
.nolfn: |
xchg esi, [esp] |
mov ecx, 11 |
rep movsb |
mov word [edi], 20h ; attributes |
sub edi, 11 |
pop esi ecx |
add esp, 12 |
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 |
and word [edi+20], 0 ; high word of cluster |
and word [edi+26], 0 ; low word of cluster - to be filled |
and dword [edi+28], 0 ; file size - to be filled |
cmp byte [esp+28+28], 0 |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov ecx, 32*2 |
mov edx, edi |
.doit: |
lea eax, [esp+8] |
call dword [eax+12] ; flush directory |
push ecx |
push edi |
push 0 |
mov esi, edx |
test ecx, ecx |
jz .done |
mov ecx, 2849 |
mov edi, FLOPPY_FAT |
push 0 ; first cluster |
.write_loop: |
; allocate new cluster |
xor eax, eax |
repnz scasw |
mov al, ERROR_DISK_FULL |
jnz .ret |
dec edi |
dec edi |
mov eax, edi |
sub eax, FLOPPY_FAT |
shr eax, 1 ; eax = cluster |
mov word [edi], 0xFFF ; mark as last cluster |
xchg edi, [esp+4] |
cmp dword [esp], 0 |
jz .first |
stosw |
jmp @f |
.first: |
mov [esp], eax |
@@: |
mov edi, [esp+4] |
inc ecx |
; write data |
push ecx edi |
mov ecx, 512 |
cmp dword [esp+20], ecx |
jae @f |
mov ecx, [esp+20] |
@@: |
mov edi, FDD_BUFF |
cmp byte [esp+24+28+28], 0 |
jnz .writedir |
push ecx |
rep movsb |
pop ecx |
.writedircont: |
push ecx |
sub ecx, 512 |
neg ecx |
push eax |
xor eax, eax |
rep stosb |
pop eax |
add eax, 31 |
pusha |
call save_chs_sector |
popa |
pop ecx |
cmp [FDC_Status], 0 |
jnz .diskerr |
sub [esp+20], ecx |
pop edi ecx |
jnz .write_loop |
.done: |
xor eax, eax |
.ret: |
pop ebx edi edi ecx |
mov [esp+28+28], eax |
lea eax, [esp+8] |
call dword [eax+4] |
mov [edi+26], bx |
mov ebx, esi |
sub ebx, edx |
mov [edi+28], ebx |
call dword [eax+12] |
mov [esp+28+16], ebx |
test ebp, ebp |
jnz @f |
call save_flp_root |
@@: |
add esp, 28 |
cmp [FDC_Status], 0 |
jnz .err3 |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .err3 |
popa |
ret |
.err3: |
popa |
mov al, 11 |
xor ebx, ebx |
ret |
.diskerr: |
sub esi, ecx |
mov eax, 11 |
pop edi ecx |
jmp .ret |
.writedir: |
push ecx |
mov ecx, 32/4 |
push ecx esi |
rep movsd |
pop esi ecx |
mov dword [edi-32], '. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov word [edi-32+26], ax |
push esi |
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+28+8] |
mov word [edi-32+26], cx |
pop ecx |
jmp .writedircont |
;---------------------------------------------------------------- |
; |
; fs_FloppyWrite - LFN variant for writing to floppy |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = bytes written (maybe 0) |
; eax = 0 ok write or other = errormsg |
; |
;-------------------------------------------------------------- |
@@: |
push ERROR_ACCESS_DENIED |
fs_FloppyWrite.ret0: |
pop eax |
xor ebx, ebx |
ret |
fs_FloppyWrite.ret11: |
push 11 |
jmp fs_FloppyWrite.ret0 |
fs_FloppyWrite: |
cmp byte [esi], 0 |
jz @b |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz .ret11 |
pushad |
call fd_find_lfn |
jnc .found |
popad |
push ERROR_FILE_NOT_FOUND |
jmp .ret0 |
.found: |
; FAT does not support files larger than 4GB |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
.eof: |
popad |
push ERROR_END_OF_FILE |
jmp .ret0 |
@@: |
mov ebx, [ebx] |
.l1: |
; 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 eax ; save directory cluster |
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 floppy_extend_file |
jnc .length_ok |
mov [esp+4], eax |
; floppy_extend_file can return two error codes: FAT table error or disk full. |
; First case is fatal error, in second case we may write some data |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax |
pop eax |
mov [esp+4+28], eax |
pop eax |
popad |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
.ret: |
pop eax |
pop eax |
mov [esp+4+28], eax ; eax=return value |
pop eax |
sub edx, [esp+20] |
mov [esp+16], edx ; ebx=number of written bytes |
popad |
ret |
.length_ok: |
; save FAT & directory |
; note that directory must be saved first because save_flp_fat uses buffer at 0xD000 |
mov esi, [edi+28] |
movzx edi, word [edi+26] ; starting cluster |
mov eax, [esp+8] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err |
call save_flp_fat |
cmp [FDC_Status], 0 |
jz @f |
.device_err: |
mov byte [esp+4], 11 |
jmp .ret |
@@: |
; now ebx=start pos, ecx=end pos, both lie inside file |
sub ecx, ebx |
jz .ret |
call SetUserInterrupts |
.write_loop: |
; skip unmodified sectors |
cmp dword [esp], 0x200 |
jb .modify |
sub ebx, 0x200 |
jae .skip |
add ebx, 0x200 |
.modify: |
lea eax, [edi+31] ; current sector |
; 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 |
@@: |
; load sector if needed |
cmp dword [esp+4], 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 |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jz @f |
.device_err2: |
pop ecx |
jmp .device_err |
@@: |
.noread: |
; zero uninitialized data if file was extended (because floppy_extend_file does not this) |
push eax ecx edi |
xor eax, eax |
mov ecx, 0x200 |
sub ecx, [esp+4+12] |
jbe @f |
mov edi, FDD_BUFF |
add edi, [esp+4+12] |
rep stosb |
@@: |
; zero uninitialized data in the last sector |
mov ecx, 0x200 |
sub ecx, esi |
jbe @f |
mov edi, FDD_BUFF |
add edi, esi |
rep stosb |
@@: |
pop edi ecx eax |
; copy new data |
push eax |
mov eax, edx |
neg ebx |
jecxz @f |
add ebx, FDD_BUFF+0x200 |
call memmove |
xor ebx, ebx |
@@: |
pop eax |
; save sector |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err2 |
add edx, ecx |
sub [esp], ecx |
pop ecx |
jz .done |
.skip: |
.next_cluster: |
movzx edi, word [edi*2+FLOPPY_FAT] |
sub esi, 0x200 |
jae @f |
xor esi, esi |
@@: |
sub dword [esp], 0x200 |
jae .write_loop |
and dword [esp], 0 |
jmp .write_loop |
.done: |
mov [fdc_irq_func], fdc_null |
jmp .ret |
floppy_extend_file.zero_size: |
xor eax, eax |
jmp floppy_extend_file.start_extend |
; extends file on floppy 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_FAT_TABLE or ERROR_DISK_FULL) |
floppy_extend_file: |
push ecx |
; find the last cluster of file |
movzx eax, word [edi+26] ; first cluster |
mov ecx, [edi+28] |
jecxz .zero_size |
@@: |
sub ecx, 0x200 |
jbe @f |
mov eax, [eax*2+FLOPPY_FAT] |
and eax, 0xFFF |
jz .fat_err |
cmp eax, 0xFF8 |
jb @b |
.fat_err: |
pop ecx |
push ERROR_FAT_TABLE |
pop eax |
stc |
ret |
@@: |
push eax |
mov eax, [eax*2+FLOPPY_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
pop eax |
jb .fat_err |
; set length to full number of sectors |
sub [edi+28], ecx |
.start_extend: |
pop ecx |
; now do extend |
push edx esi |
mov esi, FLOPPY_FAT+2*2 ; start scan from cluster 2 |
mov edx, 2847 ; number of clusters to scan |
.extend_loop: |
cmp [edi+28], ecx |
jae .extend_done |
; add new sector |
push ecx |
push edi |
.scan: |
mov ecx, edx |
mov edi, esi |
jecxz .disk_full |
push eax |
xor eax, eax |
repnz scasw |
pop eax |
jnz .disk_full |
mov word [edi-2], 0xFFF |
mov esi, edi |
mov edx, ecx |
sub edi, FLOPPY_FAT |
shr edi, 1 |
dec edi ; now edi=new cluster |
test eax, eax |
jz .first_cluster |
mov [FLOPPY_FAT+eax*2], di |
jmp @f |
.first_cluster: |
pop eax ; eax->direntry |
push eax |
mov [eax+26], di |
@@: |
mov eax, edi ; eax=new cluster |
pop edi ; edi->direntry |
pop ecx ; ecx=required size |
add dword [edi+28], 0x200 |
jmp .extend_loop |
.extend_done: |
mov [edi+28], ecx |
pop esi edx |
xor eax, eax ; CF=0 |
ret |
.disk_full: |
pop edi ecx |
pop esi edx |
stc |
push ERROR_DISK_FULL |
pop eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppySetFileEnd - set end of file on floppy |
; |
; esi points to filename |
; ebx points to 64-bit number = new file size |
; ecx ignored (reserved) |
; edx ignored (reserved) |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_FloppySetFileEnd: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
jmp .ret |
@@: |
push edi |
call fd_find_lfn |
jnc @f |
pop edi |
push ERROR_FILE_NOT_FOUND |
.ret: |
pop eax |
jmp .doret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jz @f |
pop edi |
jmp .access_denied |
@@: |
; file size must not exceed 4 Gb |
cmp dword [ebx+4], 0 |
jz @f |
pop edi |
push ERROR_END_OF_FILE |
jmp .ret |
@@: |
push eax |
; set file modification date/time to current |
call fat_update_datetime |
mov eax, [ebx] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop eax |
pushad |
call save_chs_sector |
popad |
pop edi |
xor eax, eax |
cmp [FDC_Status], 0 |
jz @f |
mov al, 11 |
@@: |
.doret: |
mov [fdc_irq_func], fdc_null |
ret |
.expand: |
push ecx |
push dword [edi+28] ; save old size |
mov ecx, eax |
call floppy_extend_file |
push eax ; return code |
jnc .expand_ok |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax ecx ecx edi edi |
jmp .doret |
.device_err: |
pop eax |
.device_err2: |
pop ecx ecx eax edi |
push 11 |
jmp .ret |
.disk_full: |
.expand_ok: |
; save directory & FAT |
mov eax, [edi+28] |
xchg eax, [esp+12] |
movzx edi, word [edi+26] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .device_err |
call SetUserInterrupts |
; now zero new data |
; edi = current cluster, [esp+12]=new size, [esp+4]=old size, [esp]=return code |
.zero_loop: |
sub dword [esp+4], 0x200 |
jae .next_cluster |
cmp dword [esp+4], -0x200 |
jz .noread |
lea eax, [edi+31] |
pusha |
call read_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .err_next |
.noread: |
mov ecx, [esp+4] |
neg ecx |
push edi |
mov edi, FDD_BUFF+0x200 |
add edi, [esp+8] |
xor eax, eax |
mov [esp+8], eax |
rep stosb |
pop edi |
lea eax, [edi+31] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jz .next_cluster |
.err_next: |
mov byte [esp], 11 |
.next_cluster: |
sub dword [esp+12], 0x200 |
jbe .expand_done |
movzx edi, word [FLOPPY_FAT+edi*2] |
jmp .zero_loop |
.expand_done: |
pop eax ecx ecx edi edi |
jmp .doret |
.truncate: |
mov [edi+28], eax |
push ecx |
movzx ecx, word [edi+26] |
test eax, eax |
jz .zero_size |
; find new last sector |
@@: |
sub eax, 0x200 |
jbe @f |
movzx ecx, word [FLOPPY_FAT+ecx*2] |
jmp @b |
@@: |
; we will zero data at the end of last sector - remember it |
push ecx |
; terminate FAT chain |
lea ecx, [FLOPPY_FAT+ecx+ecx] |
push dword [ecx] |
mov word [ecx], 0xFFF |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.zero_size: |
and word [edi+26], 0 |
push 0 |
.delete: |
; delete FAT chain starting with ecx |
; mark all clusters as free |
cmp ecx, 0xFF8 |
jae .deleted |
lea ecx, [FLOPPY_FAT+ecx+ecx] |
push dword [ecx] |
and word [ecx], 0 |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.deleted: |
mov edi, [edi+28] |
; save directory & FAT |
mov eax, [esp+8] |
pusha |
call save_chs_sector |
popa |
cmp [FDC_Status], 0 |
jnz .device_err2 |
call save_flp_fat |
cmp [FDC_Status], 0 |
jnz .device_err2 |
; zero last sector, ignore errors |
pop eax |
add eax, 31 |
and edi, 0x1FF |
jz .truncate_done |
call SetUserInterrupts |
pusha |
call read_chs_sector |
popa |
add edi, FDD_BUFF |
mov ecx, FDD_BUFF+0x200 |
sub ecx, edi |
push eax |
xor eax, eax |
rep stosb |
pop eax |
pusha |
call save_chs_sector |
popa |
.truncate_done: |
pop ecx eax edi |
xor eax, eax |
jmp .doret |
fs_FloppyGetFileInfo: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call fd_find_lfn |
jmp fs_GetFileInfo_finish |
ret11: |
mov eax, 11 |
ret |
fs_FloppySetFileInfo: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jnz ret11 |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call fd_find_lfn |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
push eax |
call bdfe_to_fat_entry |
pop eax |
pusha |
call save_chs_sector |
popa |
pop edi |
xor eax, eax |
cmp [FDC_Status], al |
jz @f |
mov al, 11 |
@@: |
ret |
;---------------------------------------------------------------- |
; |
; fs_FloppyDelete - delete file or empty folder from floppy |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_FloppyDelete: |
call read_flp_fat |
cmp [FDC_Status], 0 |
jz @f |
push 11 |
jmp .pop_ret |
@@: |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
.pop_ret: |
pop eax |
ret |
@@: |
and [fd_prev_sector], 0 |
and [fd_prev_prev_sector], 0 |
push edi |
call fd_find_lfn |
jnc .found |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .pop_ret |
.found: |
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! |
push eax |
movzx eax, word [edi+26] |
push ebx |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov ebx, FDD_BUFF + 2*0x20 |
.checkempty: |
cmp byte [ebx], 0 |
jz .empty |
cmp byte [ebx], 0xE5 |
jnz .notempty |
add ebx, 0x20 |
cmp ebx, FDD_BUFF + 0x200 |
jb .checkempty |
movzx eax, word [FLOPPY_FAT + eax*2] |
pusha |
add eax, 31 |
call read_chs_sector |
popa |
mov ebx, FDD_BUFF |
jmp .checkempty |
.notempty: |
pop ebx |
pop eax |
.access_denied2: |
pop edi |
jmp .access_denied |
.empty: |
pop ebx |
pop eax |
pusha |
call read_chs_sector |
popa |
.dodel: |
push eax |
movzx eax, word [edi+26] |
xchg eax, [esp] |
; delete folder entry |
mov byte [edi], 0xE5 |
; delete LFN (if present) |
.lfndel: |
cmp edi, FDD_BUFF |
ja @f |
cmp [fd_prev_sector], 0 |
jz .lfndone |
push [fd_prev_sector] |
push [fd_prev_prev_sector] |
pop [fd_prev_sector] |
and [fd_prev_prev_sector], 0 |
pusha |
call save_chs_sector |
popa |
pop eax |
pusha |
call read_chs_sector |
popa |
mov edi, FDD_BUFF+0x200 |
@@: |
sub edi, 0x20 |
cmp byte [edi], 0xE5 |
jz .lfndone |
cmp byte [edi+11], 0xF |
jnz .lfndone |
mov byte [edi], 0xE5 |
jmp .lfndel |
.lfndone: |
pusha |
call save_chs_sector |
popa |
; delete FAT chain |
pop eax |
test eax, eax |
jz .done |
@@: |
lea eax, [FLOPPY_FAT + eax*2] |
push dword [eax] |
and word [eax], 0 |
pop eax |
and eax, 0xFFF |
jnz @b |
.done: |
call save_flp_fat |
pop edi |
xor eax, eax |
ret |
; \end{diamond} |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/fat32.inc |
---|
0,0 → 1,2943 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; FAT32.INC ;; |
;; ;; |
;; FAT16/32 functions for KolibriOS ;; |
;; ;; |
;; Copyright 2002 Paolo Minazzi, paolo.minazzi@inwind.it ;; |
;; ;; |
;; See file COPYING for details ;; |
;; 04.02.2007 LFN create folder - diamond ;; |
;; 08.10.2006 LFN delete file/folder - diamond ;; |
;; 20.08.2006 LFN set file size (truncate/extend) - diamond ;; |
;; 17.08.2006 LFN write/append to file - diamond ;; |
;; 23.06.2006 LFN start application - diamond ;; |
;; 15.06.2006 LFN get/set file/folder info - diamond ;; |
;; 27.05.2006 LFN create/rewrite file - diamond ;; |
;; 04.05.2006 LFN read folder - diamond ;; |
;; 29.04.2006 Elimination of hangup after the ;; |
;; expiration hd_wait_timeout - Mario79 ;; |
;; 23.04.2006 LFN read file - diamond ;; |
;; 28.01.2006 find all Fat16/32 partition in all input point ;; |
;; to MBR, see file part_set.inc - Mario79 ;; |
;; 15.01.2005 get file size/attr/date, file_append - ATV ;; |
;; 04.12.2004 skip volume label, file delete bug fixed - ATV ;; |
;; 29.11.2004 get_free_FAT changed, append dir bug fixed - ATV ;; |
;; 23.11.2004 don't allow overwrite dir with file - ATV ;; |
;; 18.11.2004 get_disk_info and more error codes - ATV ;; |
;; 17.11.2004 set_FAT/get_FAT and disk cache rewritten - ATV ;; |
;; 10.11.2004 removedir clear whole directory structure - ATV ;; |
;; 08.11.2004 rename - ATV ;; |
;; 30.10.2004 file_read return also dirsize in bytes - ATV ;; |
;; 20.10.2004 Makedir/Removedir - ATV ;; |
;; 14.10.2004 Partition chain/Fat16 - ATV (thanks drh3xx) ;; |
;; 06.9.2004 Fix free space by Mario79 added - MH ;; |
;; 24.5.2004 Write back buffer for File_write -VT ;; |
;; 20.5.2004 File_read function to work with syscall 58 - VT ;; |
;; 30.3.2004 Error parameters at function return - VT ;; |
;; 01.5.2002 Bugfix in device write - VT ;; |
;; 20.5.2002 Hd status check - VT ;; |
;; 29.6.2002 Improved fat32 verification - VT ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
cache_max equ 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 |
p PARTITION ; must be the first item |
fs_type db ? |
fat16_root db 0 ; flag for fat16 rootdir |
fat_change db 0 ; 1=fat has changed |
db ? ; alignment |
Lock MUTEX ? ; currently operations with one partition |
; can not be executed in parallel since the |
; legacy code is not ready; this mutex guards |
; all operations |
SECTORS_PER_FAT dd 0x1f3a |
NUMBER_OF_FATS dd 0x2 |
SECTORS_PER_CLUSTER dd 0x8 |
BYTES_PER_SECTOR dd 0x200 ; Note: if BPS <> 512 need lots of changes |
ROOT_CLUSTER dd 2 ; first rootdir cluster |
FAT_START dd 0 ; start of fat table |
ROOT_START dd 0 ; start of rootdir (only fat16) |
ROOT_SECTORS dd 0 ; count of rootdir sectors (only fat16) |
DATA_START dd 0 ; start of data area (=first cluster 2) |
LAST_CLUSTER dd 0 ; last availabe cluster |
ADR_FSINFO dd 0 ; used only by fat32 |
fatRESERVED dd 0x0FFFFFF6 |
fatBAD dd 0x0FFFFFF7 |
fatEND dd 0x0FFFFFF8 |
fatMASK dd 0x0FFFFFFF |
fatStartScan dd 2 |
cluster_tmp dd 0 ; used by analyze_directory |
; and analyze_directory_to_write |
longname_sec1 dd 0 ; used by analyze_directory to save 2 previous |
longname_sec2 dd 0 ; directory sectors for delete long filename |
fat_in_cache dd -1 |
fat_cache rb 512 |
buffer rb 512 |
fsinfo_buffer rb 512 |
ends |
uglobal |
align 4 |
partition_count dd 0 ; partitions found by set_FAT32_variables |
hd_error dd 0 ; set by wait_for_sector_buffer |
hd_setup dd 0 |
hd_wait_timeout dd 0 |
cache_search_start dd 0 ; used by find_empty_slot |
endg |
uglobal |
align 4 |
Sector512: ; label for dev_hdcd.inc |
buffer: |
times 512 db 0 |
endg |
iglobal |
align 4 |
fat_user_functions: |
dd (fat_user_functions_end - fat_user_functions - 4) / 4 |
dd fat_Read |
dd fat_ReadFolder |
dd fat_Rewrite |
dd fat_Write |
dd fat_SetFileEnd |
dd fat_GetFileInfo |
dd fat_SetFileInfo |
dd 0 |
dd fat_Delete |
dd fat_CreateFolder |
fat_user_functions_end: |
endg |
; these labels are located before the main function to make |
; most of jumps to these be short |
fat_create_partition.free_return0: |
push ebx |
mov eax, ebp |
call free |
pop ebx |
pop ebp |
fat_create_partition.return0: |
xor eax, eax |
ret |
fat_create_partition: |
; bootsector must have been successfully read |
cmp dword [esp+4], 1 |
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. |
push ebx |
push sizeof.FAT |
pop eax |
call malloc |
pop ebx |
test eax, eax |
jz .return0 |
mov ecx, [ebp+8] |
mov dword [eax+FAT.p.FirstSector], ecx |
mov ecx, [ebp+12] |
mov dword [eax+FAT.p.FirstSector+4], ecx |
mov ecx, [ebp+16] |
mov dword [eax+FAT.p.Length], ecx |
mov ecx, [ebp+20] |
mov dword [eax+FAT.p.Length+4], ecx |
mov [eax+FAT.p.Disk], esi |
mov [eax+FAT.p.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 |
imul eax, [ebp+FAT.SECTORS_PER_FAT] |
add eax, [ebp+FAT.FAT_START] |
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 |
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 |
@@: |
mov dword [ebp+FAT.p.Length], eax |
and dword [ebp+FAT.p.Length+4], 0 |
sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors |
xor edx, edx |
div [ebp+FAT.SECTORS_PER_CLUSTER] |
inc eax |
mov [ebp+FAT.LAST_CLUSTER], eax |
dec eax ; cluster count |
mov [ebp+FAT.fatStartScan], 2 |
; limits by Microsoft Hardware White Paper v1.03 |
cmp eax, 4085 ; 0xff5 |
jb .free_return0 ; fat12 not supported |
cmp eax, 65525 ; 0xfff5 |
jb .fat16 |
.fat32: |
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 |
mov [fs_type], al |
mov [ebp+FAT.fs_type], al |
mov eax, ebp |
pop ebp |
ret |
.fat16: |
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 |
mov [fs_type], al |
mov [ebp+FAT.fs_type], al |
mov eax, ebp |
pop ebp |
ret |
set_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; EDX = value to save |
; EBP = pointer to FAT structure |
; output : EDX = old value |
;-------------------------------- |
; out: CF set <=> error |
push eax ebx esi |
cmp eax, 2 |
jb sfc_error |
cmp eax, [ebp+FAT.LAST_CLUSTER] |
ja sfc_error |
cmp [ebp+FAT.fs_type], 16 |
je sfc_1 |
add eax, eax |
sfc_1: |
add eax, eax |
mov esi, 511 |
and esi, eax ; esi = position in fat sector |
shr eax, 9 ; eax = fat sector |
add eax, [ebp+FAT.FAT_START] |
lea ebx, [ebp+FAT.fat_cache] |
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? |
je sfc_in_cache ; yes |
cmp [ebp+FAT.fat_change], 0; is fat changed? |
je sfc_no_change ; no |
call write_fat_sector; yes. write it into disk |
jc sfc_error |
sfc_no_change: |
mov [ebp+FAT.fat_in_cache], eax; save fat sector |
call fs_read32_sys |
test eax, eax |
jne sfc_error |
sfc_in_cache: |
cmp [ebp+FAT.fs_type], 16 |
jne sfc_test32 |
sfc_set16: |
xchg [ebx+esi], dx ; save new value and get old value |
jmp sfc_write |
sfc_test32: |
mov eax, [ebp+FAT.fatMASK] |
sfc_set32: |
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 |
sfc_write: |
mov [ebp+FAT.fat_change], 1; fat has changed |
sfc_nonzero: |
and edx, [ebp+FAT.fatMASK] |
sfc_return: |
pop esi ebx eax |
ret |
sfc_error: |
stc |
jmp sfc_return |
get_FAT: |
;-------------------------------- |
; input : EAX = cluster |
; EBP = pointer to FAT structure |
; output : EAX = next cluster |
;-------------------------------- |
; out: CF set <=> error |
push ebx esi |
cmp [ebp+FAT.fs_type], 16 |
je gfc_1 |
add eax, eax |
gfc_1: |
add eax, eax |
mov esi, 511 |
and esi, eax ; esi = position in fat sector |
shr eax, 9 ; eax = fat sector |
add eax, [ebp+FAT.FAT_START] |
lea ebx, [ebp+FAT.fat_cache] |
cmp eax, [ebp+FAT.fat_in_cache]; is fat sector already in memory? |
je gfc_in_cache |
cmp [ebp+FAT.fat_change], 0; is fat changed? |
je gfc_no_change ; no |
call write_fat_sector; yes. write it into disk |
jc hd_error_01 |
gfc_no_change: |
mov [ebp+FAT.fat_in_cache], eax |
call fs_read32_sys |
test eax, eax |
jne hd_error_01 |
gfc_in_cache: |
mov eax, [ebx+esi] |
and eax, [ebp+FAT.fatMASK] |
gfc_return: |
pop esi ebx |
ret |
hd_error_01: |
stc |
jmp gfc_return |
get_free_FAT: |
;----------------------------------------------------------- |
; output : if CARRY=0 EAX = # first cluster found free |
; if CARRY=1 disk full |
; Note : for more speed need to use fat_cache directly |
;----------------------------------------------------------- |
push ecx |
mov ecx, [ebp+FAT.LAST_CLUSTER]; counter for full disk |
sub ecx, 2 |
mov eax, [ebp+FAT.fatStartScan] |
cmp eax, 2 |
jb gff_reset |
gff_test: |
cmp eax, [ebp+FAT.LAST_CLUSTER]; if above last cluster start at cluster 2 |
jbe gff_in_range |
gff_reset: |
mov eax, 2 |
gff_in_range: |
push eax |
call get_FAT ; get cluster state |
jc gff_not_found_1 |
test eax, eax ; is it free? |
pop eax |
je gff_found ; yes |
inc eax ; next cluster |
dec ecx ; is all checked? |
jns gff_test ; no |
gff_not_found: |
pop ecx ; yes. disk is full |
stc |
ret |
gff_not_found_1: |
pop eax |
jmp gff_not_found |
gff_found: |
lea ecx, [eax+1] |
mov [ebp+FAT.fatStartScan], ecx |
pop ecx |
clc |
ret |
write_fat_sector: |
;----------------------------------------------------------- |
; write changed fat to disk |
;----------------------------------------------------------- |
push eax ebx ecx |
mov [ebp+FAT.fat_change], 0 |
mov eax, [ebp+FAT.fat_in_cache] |
cmp eax, -1 |
jz write_fat_not_used |
lea ebx, [ebp+FAT.fat_cache] |
mov ecx, [ebp+FAT.NUMBER_OF_FATS] |
write_next_fat: |
push eax |
call fs_write32_sys |
test eax, eax |
pop eax |
jnz write_fat_not_used |
add eax, [ebp+FAT.SECTORS_PER_FAT] |
dec ecx |
jnz write_next_fat |
write_fat_not_used: |
pop ecx ebx eax |
ret |
bcd2bin: |
;---------------------------------- |
; input : AL=BCD number (eg. 0x11) |
; output : AH=0 |
; AL=decimal number (eg. 11) |
;---------------------------------- |
xor ah, ah |
shl ax, 4 |
shr al, 4 |
aad |
ret |
get_date_for_file: |
;----------------------------------------------------- |
; Get date from CMOS and pack day,month,year in AX |
; DATE bits 0..4 : day of month 0..31 |
; 5..8 : month of year 1..12 |
; 9..15 : count of years from 1980 |
;----------------------------------------------------- |
mov al, 0x7 ;day |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 5 |
mov al, 0x8 ;month |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 4 |
mov al, 0x9 ;year |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
add ax, 20 ;because CMOS return only the two last |
;digit (eg. 2000 -> 00 , 2001 -> 01) and we |
rol eax, 9 ;need the difference with 1980 (eg. 2001-1980) |
ret |
get_time_for_file: |
;----------------------------------------------------- |
; Get time from CMOS and pack hour,minute,second in AX |
; TIME bits 0..4 : second (the low bit is lost) |
; 5..10 : minute 0..59 |
; 11..15 : hour 0..23 |
;----------------------------------------------------- |
mov al, 0x0 ;second |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 6 |
mov al, 0x2 ;minute |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
ror eax, 6 |
mov al, 0x4 ;hour |
out 0x70, al |
in al, 0x71 |
call bcd2bin |
rol eax, 11 |
ret |
set_current_time_for_entry: |
;----------------------------------------------------- |
; Set current time/date for file entry |
; input : ebx = file entry pointer |
;----------------------------------------------------- |
push eax |
call get_time_for_file; update files date/time |
mov [ebx+22], ax |
call get_date_for_file |
mov [ebx+24], ax |
pop eax |
ret |
add_disk_free_space: |
;----------------------------------------------------- |
; input : ecx = cluster count |
; Note : negative = remove clusters from free space |
; positive = add clusters to free space |
;----------------------------------------------------- |
test ecx, ecx ; no change |
je add_dfs_no |
cmp [ebp+FAT.fs_type], 32 ; free disk space only used by fat32 |
jne add_dfs_no |
push eax ebx |
mov eax, [ebp+FAT.ADR_FSINFO] |
lea ebx, [ebp+FAT.fsinfo_buffer] |
call fs_read32_sys |
test eax, eax |
jnz add_not_fs |
cmp dword [ebx+0x1fc], 0xaa550000; check sector id |
jne add_not_fs |
add [ebx+0x1e8], ecx |
push [ebp+FAT.fatStartScan] |
pop dword [ebx+0x1ec] |
mov eax, [ebp+FAT.ADR_FSINFO] |
call fs_write32_sys |
; jc add_not_fs |
add_not_fs: |
pop ebx eax |
add_dfs_no: |
ret |
clear_cluster_chain: |
;----------------------------------------------------- |
; input : eax = first cluster |
;----------------------------------------------------- |
push eax ecx edx |
xor ecx, ecx ; cluster count |
clean_new_chain: |
cmp eax, [ebp+FAT.LAST_CLUSTER]; end of file |
ja delete_OK |
cmp eax, 2 ; unfinished fat chain or zero length file |
jb delete_OK |
cmp eax, [ebp+FAT.ROOT_CLUSTER]; don't remove root cluster |
jz delete_OK |
xor edx, edx |
call set_FAT ; clear fat entry |
jc access_denied_01 |
inc ecx ; update cluster count |
mov eax, edx ; old cluster |
jmp clean_new_chain |
delete_OK: |
call add_disk_free_space; add clusters to free disk space |
clc |
access_denied_01: |
pop edx ecx eax |
ret |
if 0 |
get_hd_info: |
;----------------------------------------------------------- |
; output : eax = 0 - ok |
; 3 - unknown FS |
; 10 - access denied |
; edx = cluster size in bytes |
; ebx = total clusters on disk |
; ecx = free clusters on disk |
;----------------------------------------------------------- |
cmp [ebp+FAT.fs_type], 16 |
jz info_fat_ok |
cmp [ebp+FAT.fs_type], 32 |
jz info_fat_ok |
xor edx, edx |
xor ebx, ebx |
xor ecx, ecx |
mov eax, ERROR_UNKNOWN_FS |
ret |
info_fat_ok: |
; call reserve_hd1 |
xor ecx, ecx ; count of free clusters |
mov eax, 2 |
mov ebx, [ebp+FAT.LAST_CLUSTER] |
info_cluster: |
push eax |
call get_FAT ; get cluster info |
jc info_access_denied |
test eax, eax ; is it free? |
jnz info_used ; no |
inc ecx |
info_used: |
pop eax |
inc eax |
cmp eax, ebx ; is above last cluster? |
jbe info_cluster ; no. test next cluster |
dec ebx ; cluster count |
imul edx, [ebp+FAT.SECTORS_PER_CLUSTER], 512; cluster size in bytes |
xor eax, eax |
ret |
info_access_denied: |
add esp, 4 |
xor edx, edx |
xor ebx, ebx |
xor ecx, ecx |
mov eax, ERROR_ACCESS_DENIED |
ret |
end if |
update_disk: |
;----------------------------------------------------------- |
; write changed fat and cache to disk |
;----------------------------------------------------------- |
cmp [ebp+FAT.fat_change], 0 ; is fat changed? |
je upd_no_change |
call write_fat_sector |
jc update_disk_acces_denied |
upd_no_change: |
push esi |
mov esi, [ebp+PARTITION.Disk] |
call disk_sync |
pop esi |
update_disk_acces_denied: |
ret |
fat_lock: |
lea ecx, [ebp+FAT.Lock] |
jmp mutex_lock |
fat_unlock: |
lea ecx, [ebp+FAT.Lock] |
jmp mutex_unlock |
; \begin{diamond} |
hd_find_lfn: |
; in: ebp -> FAT structure |
; in: esi+[esp+4] -> name |
; out: CF=1 - file not found, eax=error code |
; else CF=0 and edi->direntry, eax=sector |
; destroys eax |
push esi edi |
push 0 |
push 0 |
push fat16_root_first |
push fat16_root_next |
mov eax, [ebp+FAT.ROOT_CLUSTER] |
cmp [ebp+FAT.fs_type], 32 |
jz .fat32 |
.loop: |
call fat_find_lfn |
jc .notfound |
cmp byte [esi], 0 |
jz .found |
.continue: |
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 4 |
.found: |
lea eax, [esp+4+24] |
cmp dword [eax], 0 |
jz @f |
mov esi, [eax] |
and dword [eax], 0 |
jmp .continue |
@@: |
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 4 |
;---------------------------------------------------------------- |
; |
; fs_HdRead - LFN variant for reading hard disk |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdRead: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdRead |
cmp [fs_type], 2 |
jz ext2_HdRead |
or ebx, -1 |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_Read |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_Read - FAT16/32 implementation of reading a file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Read: |
call fat_lock |
push edi |
cmp byte [esi], 0 |
jnz @f |
.noaccess: |
pop edi |
.noaccess_2: |
call fat_unlock |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
@@: |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
pop eax |
or ebx, -1 |
ret |
.found: |
test byte [edi+11], 0x10; do not allow read directories |
jnz .noaccess |
cmp dword [ebx+8], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
call fat_unlock |
mov eax, ERROR_END_OF_FILE |
pop edi |
ret |
@@: |
mov ecx, [ebx+12] ; size |
mov edx, [ebx+16] ; pointer |
mov ebx, [ebx+4] ; file offset |
push edx |
push 0 |
mov eax, [edi+28] |
sub eax, ebx |
jb .eof |
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=position, ecx=count, edx=buffer for data |
.new_cluster: |
jecxz .new_sector |
cmp eax, 2 |
jb .eof |
cmp eax, [ebp+FAT.fatRESERVED] |
jae .eof |
mov [ebp+FAT.cluster_tmp], eax |
dec eax |
dec eax |
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER] |
imul eax, edi |
add eax, [ebp+FAT.DATA_START] |
.new_sector: |
test ecx, ecx |
jz .done |
sub ebx, 512 |
jae .skip |
add ebx, 512 |
jnz .force_buf |
cmp ecx, 512 |
jb .force_buf |
; we may read directly to given buffer |
push eax ebx |
mov ebx, edx |
call fs_read32_app |
test eax, eax |
pop ebx eax |
jne .noaccess_1 |
add edx, 512 |
sub ecx, 512 |
jmp .skip |
.force_buf: |
; we must read sector to temporary buffer and then copy it to destination |
push eax ebx |
lea ebx, [ebp+FAT.buffer] |
call fs_read32_app |
test eax, eax |
mov eax, ebx |
pop ebx |
jne .noaccess_3 |
add eax, ebx |
push ecx |
add ecx, ebx |
cmp ecx, 512 |
jbe @f |
mov ecx, 512 |
@@: |
sub ecx, ebx |
mov ebx, edx |
call memmove |
add edx, ecx |
sub [esp], ecx |
pop ecx |
pop eax |
xor ebx, ebx |
.skip: |
inc eax |
dec edi |
jnz .new_sector |
mov eax, [ebp+FAT.cluster_tmp] |
call get_FAT |
jc .noaccess_1 |
jmp .new_cluster |
.noaccess_3: |
pop eax |
.noaccess_1: |
pop eax |
push ERROR_DEVICE |
.done: |
mov ebx, edx |
call fat_unlock |
pop eax edx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx |
sub ebx, edx |
jmp .reteof |
;---------------------------------------------------------------- |
; |
; fs_HdReadFolder - LFN variant for reading hard disk folder |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; ebx pointer to structure 32-bit number = first wanted block, 0+ |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = blocks read or 0xffffffff folder not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdReadFolder: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdReadFolder |
cmp [fs_type], 2 |
jz ext2_HdReadFolder |
push ERROR_UNSUPPORTED_FS |
pop eax |
or ebx, -1 |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_ReadFolder |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_ReadFolder - FAT16/32 implementation of reading a folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_ReadFolder: |
call fat_lock |
mov eax, [ebp+FAT.ROOT_CLUSTER] |
push edi |
cmp byte [esi], 0 |
jz .doit |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
pop eax |
or ebx, -1 |
ret |
.found: |
test byte [edi+11], 0x10 ; do not allow read files |
jnz .found_dir |
pop edi |
call fat_unlock |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
mov eax, [edi+20-2] |
mov ax, [edi+26] ; eax=cluster |
.doit: |
push esi |
sub esp, 262*2 ; reserve space for LFN |
push dword [ebx+8] ; for fat_get_name: read ANSI/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 ebp |
lea ebp, [esp+20] |
call fat_get_name |
pop ebp |
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 |
pop esi edi |
mov ebx, [edx+4] |
call fat_unlock |
mov eax, ERROR_DEVICE |
ret |
.done: |
add esp, 262*2+4+8 |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
push eax |
call fat_unlock |
pop eax |
pop esi edi |
ret |
fat16_root_next: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200-0x20] |
cmp edi, ecx |
jae fat16_root_next_sector |
pop ecx |
add edi, 0x20 |
ret ; CF=0 |
fat16_root_next_sector: |
; read 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] |
pop ecx |
jb fat16_root_first |
mov eax, ERROR_FILE_NOT_FOUND |
stc |
ret |
fat16_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 |
jnz .readerr |
ret ; CF=0 |
.readerr: |
mov eax, ERROR_DEVICE |
stc |
ret |
.notfound: |
mov eax, ERROR_FILE_NOT_FOUND |
stc |
ret |
fat16_root_begin_write: |
push edi eax |
call fat16_root_first |
pop eax edi |
ret |
fat16_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 |
fat16_root_next_write: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200] |
cmp edi, ecx |
jae @f |
pop ecx |
ret |
@@: |
call fat16_root_end_write |
jmp fat16_root_next_sector |
fat16_root_extend_dir: |
stc |
ret |
fat_notroot_next: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200-0x20] |
cmp edi, ecx |
jae fat_notroot_next_sector |
pop ecx |
add edi, 0x20 |
ret ; CF=0 |
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_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_next_err: |
pop ecx |
mov eax, ERROR_FILE_NOT_FOUND |
stc |
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_next_write: |
push ecx |
lea ecx, [ebp+FAT.buffer+0x200] |
cmp edi, ecx |
jae @f |
pop ecx |
ret |
@@: |
push eax |
call fat_notroot_end_write |
pop eax |
jmp fat_notroot_next_sector |
fat_notroot_extend_dir: |
push eax |
call get_free_FAT |
jnc .found |
pop eax |
ret ; CF=1 |
.found: |
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 |
jnc @f |
.writeerr: |
pop edx |
pop eax |
stc |
ret |
@@: |
push ecx |
or ecx, -1 |
call add_disk_free_space |
; zero new cluster |
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 |
;---------------------------------------------------------------- |
; |
; fs_HdRewrite - LFN variant for writing hard disk |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; ebx ignored (reserved) |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = number of written bytes |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdCreateFolder: |
mov al, 1 |
jmp fs_HdRewrite.common |
fs_HdRewrite: |
xor eax, eax |
.common: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdRewrite |
cmp [fs_type], 2 |
jz ext2_HdRewrite |
mov eax, ERROR_UNKNOWN_FS |
xor ebx, ebx |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
test eax, eax |
mov eax, fat_CreateFolder |
jnz @f |
mov eax, fat_Rewrite |
@@: |
call eax |
pop ebp |
ret |
fshrad: |
call fat_unlock |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
;---------------------------------------------------------------- |
; fat_CreateFolder - FAT16/32 implementation of creating a folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_CreateFolder: |
push 1 |
jmp fat_Rewrite.common |
;---------------------------------------------------------------- |
; fat_HdRewrite - FAT16/32 implementation of creating a new file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Rewrite: |
push 0 |
.common: |
call fat_lock |
pop eax |
cmp byte [esi], 0 |
jz fshrad |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
pushad |
xor edi, edi |
mov edx, [esp+4+20h] |
push esi |
test edx, edx |
jz @f |
mov esi, edx |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea edi, [esi-1] |
jmp @b |
@@: |
pop esi |
test edi, edi |
jnz .noroot |
test edx, edx |
jnz .hasebp |
mov edx, [ebp+FAT.ROOT_CLUSTER] |
cmp [ebp+FAT.fs_type], 32 |
jz .pushnotroot |
xor edx, edx |
push edx |
push fat16_root_extend_dir |
push fat16_root_end_write |
push fat16_root_next_write |
push fat16_root_begin_write |
push edx |
push edx |
push fat16_root_first |
push fat16_root_next |
jmp .common1 |
.hasebp: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edx], 0 |
jz .ret1 |
stdcall hd_find_lfn, 0 |
mov esi, [esp+4+20h] |
jc .ret1 |
jmp .common0 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edi+1], 0 |
jz .ret1 |
; check existence |
mov byte [edi], 0 |
push edi |
stdcall hd_find_lfn, [esp+4+24h] |
pop esi |
mov byte [esi], '/' |
jnc @f |
.notfound0: |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
call fat_unlock |
popad |
xor ebx, ebx |
ret |
@@: |
inc esi |
.common0: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
mov edx, [edi+20-2] |
mov dx, [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
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 |
; found |
test byte [edi+11], 10h |
jz .exists_file |
; found directory; if we are creating directory, return OK, |
; if we are creating file, say "access denied" |
add esp, 36 |
call fat_unlock |
popad |
test al, al |
mov eax, ERROR_ACCESS_DENIED |
jz @f |
mov al, 0 |
@@: |
xor ebx, ebx |
ret |
.exists_file: |
; found file; if we are creating directory, return "access denied", |
; if we are creating file, delete existing file and continue |
cmp byte [esp+36+28], 0 |
jz @f |
add esp, 36 |
call fat_unlock |
popad |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
@@: |
; 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 |
push edx |
xor edx, edx |
call set_FAT |
mov eax, edx |
pop edx |
jc .done1 |
inc ecx |
jmp @b |
.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 |
jmp .doit |
.notfound: |
; file is not found; generate short name |
call fat_name_is_legal |
jc @f |
add esp, 36 |
call fat_unlock |
popad |
mov eax, ERROR_FILE_NOT_FOUND |
xor ebx, ebx |
ret |
@@: |
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 |
jmp .found |
.short_name_found: |
pop ecx edi esi |
call fat_next_short_name |
jnc .test_short_name_loop |
.disk_full: |
add esp, 12+36 |
call fat_unlock |
popa |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.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 |
push 1 |
pop eax ; 1 entry |
jnz .notilde |
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total |
xor eax, eax |
@@: |
cmp byte [esi], 0 |
jz @f |
inc esi |
inc eax |
jmp @b |
@@: |
sub esi, eax |
add eax, 12+13 |
mov ecx, 13 |
push edx |
cdq |
div ecx |
pop edx |
.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 |
call fat_unlock |
popad |
mov eax, ERROR_DEVICE |
xor ebx, ebx |
ret |
.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 |
call fat_unlock |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.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 now and fail immediately |
; if this is impossible. This prevents from creating an invalid directory entry |
; on a full disk. |
; yup, the argument is quite non-intuitive... but what should I do if |
; the entire function uses such arguments? BTW, it refers to al from pushad, |
; which in turn is filled with 0 in fat_Rewrite and 1 in fat_CreateFolder. |
cmp byte [esp+8+12+8+12+36+28], 0 |
jz .no.preallocate.folder.data |
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 |
.no.preallocate.folder.data: |
; 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 |
pop 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 |
push eax |
lea eax, [esp+8+8+12+8] |
call dword [eax+8] ; begin write |
mov al, 40h |
.writelfn: |
or al, cl |
mov esi, [esp+4] |
push ecx |
dec ecx |
imul ecx, 13 |
add esi, ecx |
stosb |
mov cl, 5 |
call fs_RamdiskRewrite.read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call fs_RamdiskRewrite.read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call fs_RamdiskRewrite.read_symbols |
pop ecx |
lea eax, [esp+8+8+12+8] |
call dword [eax+12] ; next write |
xor eax, eax |
loop .writelfn |
pop eax |
pop esi |
; lea eax, [esp+8+12+8] |
; call dword [eax+16] ; end write |
.nolfn: |
xchg esi, [esp] |
mov ecx, 11 |
rep movsb |
mov word [edi], 20h ; attributes |
sub edi, 11 |
pop esi ecx |
add esp, 12 |
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 |
xor ecx, ecx |
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 byte [esp+36+28], cl |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov esi, edi |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
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 |
.doit: |
mov esi, [esp+36+20] |
lea eax, [esp+8] |
call dword [eax+16] ; flush directory |
push ecx |
mov ecx, [esp+4+36+24] |
push ecx |
push edi |
test ecx, ecx |
jz .done |
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 |
push edx |
mov edx, [ebp+FAT.fatEND] |
call set_FAT |
pop edx |
.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 data |
.write_sector: |
cmp byte [esp+20+36+28], 0 |
jnz .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 |
.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 |
push edx |
mov edx, [ebp+FAT.fatEND] |
call set_FAT |
xchg eax, ecx |
mov edx, ecx |
call set_FAT |
pop edx |
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 |
.done: |
xor eax, eax |
.ret: |
pop edi ecx |
sub esi, [esp+4+36+20] |
mov [esp+4+36+28], eax |
mov [esp+4+36+16], esi |
lea eax, [esp+12] |
call dword [eax+8] |
mov [edi+28], esi |
call dword [eax+16] |
mov [esp+36+16], ebx |
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 |
call update_disk |
call fat_unlock |
popad |
ret |
.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 |
;---------------------------------------------------------------- |
; |
; fs_HdWrite - LFN variant for writing to hard disk |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = bytes written (maybe 0) |
; eax = 0 ok write or other = errormsg |
; |
;-------------------------------------------------------------- |
fat_Write.access_denied: |
push ERROR_ACCESS_DENIED |
fs_HdWrite.ret0: |
pop eax |
xor ebx, ebx |
ret |
fs_HdWrite.ret11: |
push ERROR_DEVICE |
jmp fs_HdWrite.ret0 |
fs_HdWrite: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdWrite |
cmp [fs_type], 2 |
jz ext2_HdWrite |
push ERROR_UNKNOWN_FS |
jmp .ret0 |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_Write |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_Write - FAT16/32 implementation of writing to file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Write: |
cmp byte [esi], 0 |
jz .access_denied |
call fat_lock |
push edi |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push eax |
call fat_unlock |
jmp fs_HdWrite.ret0 |
.found: |
; FAT does not support files larger than 4GB |
cmp dword [ebx+8], 0 |
jz @f |
.eof: |
pop edi |
push ERROR_END_OF_FILE |
call fat_unlock |
jmp fs_HdWrite.ret0 |
@@: |
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 |
jz .disk_full |
call fat_unlock |
pop eax |
pop eax |
pop ecx |
pop edx |
pop edi |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
push 0 |
.ret: |
pop eax |
sub edx, [esp+12] |
mov ebx, edx ; ebx=number of written bytes |
call update_disk |
test eax, eax |
jz @f |
mov byte [esp+4], ERROR_DEVICE |
@@: |
call fat_unlock |
pop eax |
pop eax |
pop ecx |
pop edx |
pop edi |
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 |
jz @f |
.device_err: |
mov byte [esp+8], ERROR_DEVICE |
jmp .ret |
.fat_err: |
mov byte [esp+8], ERROR_FAT_TABLE |
jmp .ret |
@@: |
; 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 |
jz @f |
.device_err2: |
pop ecx |
jmp .device_err |
@@: |
.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_FAT_TABLE 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_FAT_TABLE |
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 |
push ERROR_DISK_FULL |
pop eax |
stc |
ret |
;---------------------------------------------------------------- |
; |
; fs_HdSetFileEnd - set end of file on hard disk |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; ebx points to 64-bit number = new file size |
; ecx ignored (reserved) |
; edx ignored (reserved) |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdSetFileEnd: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdSetFileEnd |
cmp [fs_type], 2 |
jz ext2_HdSetFileEnd |
push ERROR_UNKNOWN_FS |
pop eax |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_SetFileEnd |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_SetFileEnd - FAT16/32 implementation of setting end-of-file |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_SetFileEnd: |
call fat_lock |
push edi |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
.ret: |
call fat_unlock |
pop eax |
pop edi |
ret |
@@: |
stdcall hd_find_lfn, [esp+4+4] |
jnc @f |
.reteax: |
push eax |
jmp .ret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jnz .access_denied |
; file size must not exceed 4 Gb |
cmp dword [ebx+8], 0 |
jz @f |
push ERROR_END_OF_FILE |
jmp .ret |
@@: |
push eax ; save directory sector |
; set file modification date/time to current |
call fat_update_datetime |
mov eax, [ebx+4] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop eax |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
pop edi |
test eax, eax |
jz @f |
push ERROR_DEVICE |
jmp .ret |
@@: |
push 0 |
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 |
jz .disk_full |
.pop_ret: |
call update_disk |
pop eax ecx ecx ebp ebx ecx |
jmp .reteax |
.expand_ok: |
.disk_full: |
; save directory |
mov eax, [edi+28] |
xchg eax, [esp+20] |
lea ebx, [ebp+FAT.buffer] |
call fs_write32_sys |
test eax, eax |
mov eax, [edi+20-2] |
mov ax, [edi+26] |
mov edi, eax |
jz @f |
.pop_ret11: |
mov byte [esp], ERROR_DEVICE |
jmp .pop_ret |
@@: |
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 |
jmp .pop_ret11 |
.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 edi |
call update_disk |
call fat_unlock |
push ERROR_DEVICE |
pop eax |
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 edi |
call update_disk |
call fat_unlock |
xor eax, eax |
ret |
.error_fat: |
pop eax |
mov byte [esp], ERROR_FAT_TABLE |
jmp .pop_ret |
.error_fat2: |
pop eax ecx eax edi |
call update_disk |
call fat_unlock |
push ERROR_FAT_TABLE |
pop eax |
ret |
fs_HdGetFileInfo: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdGetFileInfo |
cmp [fs_type], 2 |
jz ext2_HdGetFileInfo |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_GetFileInfo |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_GetFileInfo - FAT16/32 implementation of getting file info |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_GetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call fat_lock |
stdcall hd_find_lfn, [esp+4+4] |
jc .error |
push ebp |
xor ebp, ebp |
mov esi, [ebx+16] |
mov dword [esi+4], ebp |
call fat_entry_to_bdfe2 |
pop ebp |
call fat_unlock |
xor eax, eax |
pop edi |
ret |
.error: |
push eax |
call fat_unlock |
pop eax |
pop edi |
ret |
fs_HdSetFileInfo: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdSetFileInfo |
cmp [fs_type], 2 |
jz ext2_HdSetFileInfo |
mov eax, ERROR_UNKNOWN_FS |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_SetFileInfo |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_SetFileInfo - FAT16/32 implementation of setting file info |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_SetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call fat_lock |
stdcall hd_find_lfn, [esp+4+4] |
jc .error |
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 |
call fat_unlock |
pop edi |
xor eax, eax |
ret |
.error: |
push eax |
call fat_unlock |
pop eax |
pop edi |
ret |
;---------------------------------------------------------------- |
; |
; fs_HdDelete - delete file or empty folder from hard disk |
; |
; Obsolete, will be replaced with filesystem-specific functions. |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_HdDelete: |
cmp [fs_type], 16 |
jz @f |
cmp [fs_type], 32 |
jz @f |
cmp [fs_type], 1 |
jz ntfs_HdDelete |
cmp [fs_type], 2 |
jz ext2_HdDelete |
push ERROR_UNKNOWN_FS |
pop eax |
ret |
@@: |
sub ebx, 4 |
push ebp |
mov ebp, [fs_dependent_data_start.partition] |
call fat_Delete |
pop ebp |
ret |
;---------------------------------------------------------------- |
; fat_Delete - FAT16/32 implementation of deleting a file/folder |
; in: ebp = pointer to FAT structure |
; in: esi+[esp+4] = name |
; in: ebx = pointer to parameters from sysfunc 70 |
; out: eax, ebx = return values for sysfunc 70 |
;---------------------------------------------------------------- |
fat_Delete: |
call fat_lock |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
.pop_ret: |
call fat_unlock |
pop eax |
xor ebx, ebx |
ret |
@@: |
and [ebp+FAT.longname_sec1], 0 |
and [ebp+FAT.longname_sec2], 0 |
push edi |
stdcall hd_find_lfn, [esp+4+4] |
jnc .found |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .pop_ret |
.found: |
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: |
pop edi |
call fat_unlock |
push ERROR_DEVICE |
pop eax |
ret |
.error_fat: |
popad |
pop edi |
call fat_unlock |
push ERROR_FAT_TABLE |
pop eax |
ret |
.notempty: |
popad |
.access_denied2: |
pop edi |
call fat_unlock |
push ERROR_ACCESS_DENIED |
pop eax |
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 |
pop edi |
xor eax, eax |
ret |
; \end{diamond} |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/fs-sp.inc |
---|
0,0 → 1,13 |
dir0: |
db 'DISCO DURO ' |
db 'UNIDAD RAM ' |
db 'DISQUETE ' |
db 0 |
dir1: |
db 'PRIMERO ' |
db 'SEGUNDO ' |
db 'TERCERO ' |
db 'CUARTO ' |
db 0 |
/kernel/branches/net/fs/fs.inc |
---|
0,0 → 1,773 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; ;; |
;; System service for filesystem call ;; |
;; (C) 2004 Ville Turjanmaa, License: GPL ;; |
;; 29.04.2006 Elimination of hangup after the ;; |
;; expiration hd_wait_timeout (for LBA) - Mario79 ;; |
;; 15.01.2005 get file size/attr/date, ;; |
;; file_append (only for hd) - ATV ;; |
;; 23.11.2004 test if hd/partition is set - ATV ;; |
;; 18.11.2004 get_disk_info and more error codes - ATV ;; |
;; 08.11.2004 expand_pathz and rename (only for hd) - ATV ;; |
;; 20.10.2004 Makedir/Removedir (only for hd) - ATV ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
iglobal |
if lang eq sp |
include 'fs/fs-sp.inc' |
else |
dir0: |
db 'HARDDISK ' |
db 'RAMDISK ' |
db 'FLOPPYDISK ' |
db 0 |
dir1: |
db 'FIRST ' |
db 'SECOND ' |
db 'THIRD ' |
db 'FOURTH ' |
db 0 |
end if |
not_select_IDE db 0 |
hd_address_table: |
dd 0x1f0,0x00,0x1f0,0x10 |
dd 0x170,0x00,0x170,0x10 |
endg |
file_system: |
; IN: |
; |
; eax = 0 ; read file /RamDisk/First 6 |
; eax = 8 ; lba read |
; eax = 15 ; get_disk_info |
; |
; OUT: |
; |
; eax = 0 : read ok |
; eax = 1 : no hd base and/or partition defined |
; eax = 2 : function is unsupported for this FS |
; eax = 3 : unknown FS |
; eax = 4 : partition not defined at hd |
; eax = 5 : file not found |
; eax = 6 : end of file |
; eax = 7 : memory pointer not in application area |
; eax = 8 : disk full |
; eax = 9 : fat table corrupted |
; eax = 10 : access denied |
; eax = 11 : disk error |
; |
; ebx = size |
; \begin{diamond}[18.03.2006] |
; for subfunction 16 (start application) error codes must be negative |
; because positive values are valid PIDs |
; so possible return values are: |
; eax > 0 : process created, eax=PID |
; -0x10 <= eax < 0 : -eax is filesystem error code: |
; eax = -1 = 0xFFFFFFFF : no hd base and/or partition defined |
; eax = -3 = 0xFFFFFFFD : unknown FS |
; eax = -5 = 0xFFFFFFFB : file not found |
; eax = -6 = 0xFFFFFFFA : unexpected end of file (probably not executable file) |
; eax = -9 = 0xFFFFFFF7 : fat table corrupted |
; eax = -10 = 0xFFFFFFF6 : access denied |
; -0x20 <= eax < -0x10: eax is process creation error code: |
; eax = -0x20 = 0xFFFFFFE0 : too many processes |
; eax = -0x1F = 0xFFFFFFE1 : not Menuet/Kolibri executable |
; eax = -0x1E = 0xFFFFFFE2 : no memory |
; ebx is not changed |
; \end{diamond}[18.03.2006] |
; Extract parameters |
; add eax, std_application_base_address ; abs start of info block |
cmp dword [eax+0], 15; GET_DISK_INFO |
je fs_info |
cmp dword [CURRENT_TASK], 1; no memory checks for kernel requests |
jz no_checks_for_kernel |
mov edx, eax |
cmp dword [eax+0], 1 |
jnz .usual_check |
mov ebx, [eax+12] |
; add ebx,std_application_base_address |
mov ecx, [eax+8] |
call check_region |
test eax, eax |
jnz area_in_app_mem |
.error_output: |
mov esi, buffer_failed |
call sys_msg_board_str |
; mov eax,7 |
mov dword [esp+36], 7 |
ret |
iglobal |
buffer_failed db 'K : Buffer check failed',13,10,0 |
endg |
.usual_check: |
cmp dword [eax+0], 0 |
mov ecx, 512 |
jnz .small_size |
mov ecx, [eax+8] |
shl ecx, 9 |
.small_size: |
mov ebx, [eax+12] |
; add ebx,std_application_base_address |
call check_region |
test eax, eax |
jz .error_output |
area_in_app_mem: |
mov eax, edx |
no_checks_for_kernel: |
fs_read: |
mov ebx, [eax+20] ; program wants root directory ? |
test bl, bl |
je fs_getroot |
test bh, bh |
jne fs_noroot |
fs_getroot: |
; \begin{diamond}[18.03.2006] |
; root - only read is allowed |
; other operations return "access denied", eax=10 |
; (execute operation returns eax=-10) |
cmp dword [eax], 0 |
jz .read_root |
mov dword [esp+36], 10 |
ret |
.read_root: |
; \end{diamond}[18.03.2006] |
mov esi, dir0 |
mov edi, [eax+12] |
; add edi,std_application_base_address |
mov ecx, 11 |
push ecx |
; cld ; already is |
rep movsb |
mov al, 0x10 |
stosb |
add edi, 32-11-1 |
pop ecx |
rep movsb |
stosb |
and dword [esp+36], 0; ok read |
mov dword [esp+24], 32*2; size of root |
ret |
fs_info: ;start of code - Mihasik |
push eax |
cmp [eax+21], byte 'r' |
je fs_info_r |
cmp [eax+21], byte 'R' |
je fs_info_r |
mov eax, 3 ;if unknown disk |
xor ebx, ebx |
xor ecx, ecx |
xor edx, edx |
jmp fs_info1 |
fs_info_r: |
call ramdisk_free_space;if ramdisk |
mov ecx, edi ;free space in ecx |
shr ecx, 9 ;free clusters |
mov ebx, 2847 ;total clusters |
mov edx, 512 ;cluster size |
xor eax, eax ;always 0 |
fs_info1: |
pop edi |
mov [esp+36], eax |
mov [esp+24], ebx ; total clusters on disk |
mov [esp+32], ecx ; free clusters on disk |
mov [edi], edx ; cluster size in bytes |
ret ;end of code - Mihasik |
fs_noroot: |
push dword [eax+0] ; read/write/delete/.../makedir/rename/lba/run |
push dword [eax+4] ; 512 block number to read |
push dword [eax+8] ; bytes to write/append or 512 blocks to read |
mov ebx, [eax+12] |
; add ebx,std_application_base_address |
push ebx ; abs start of return/save area |
lea esi, [eax+20] ; abs start of dir + filename |
mov edi, [eax+16] |
; add edi,std_application_base_address ; abs start of work area |
call expand_pathz |
push edi ; dir start |
push ebx ; name of file start |
mov eax, [edi+1] |
cmp eax, 'RD ' |
je fs_yesramdisk |
cmp eax, 'RAMD' |
jne fs_noramdisk |
fs_yesramdisk: |
cmp byte [edi+1+11], 0 |
je fs_give_dir1 |
mov eax, [edi+1+12] |
cmp eax, '1 ' |
je fs_yesramdisk_first |
cmp eax, 'FIRS' |
jne fs_noramdisk |
fs_yesramdisk_first: |
cmp dword [esp+20], 8; LBA read ramdisk |
jne fs_no_LBA_read_ramdisk |
mov eax, [esp+16] ; LBA block to read |
mov ecx, [esp+8] ; abs pointer to return area |
call LBA_read_ramdisk |
jmp file_system_return |
fs_no_LBA_read_ramdisk: |
cmp dword [esp+20], 0; READ |
jne fs_noramdisk_read |
mov eax, [esp+4] ; fname |
add eax, 2*12+1 |
mov ebx, [esp+16] ; block start |
inc ebx |
mov ecx, [esp+12] ; block count |
mov edx, [esp+8] ; return |
mov esi, [esp+0] |
sub esi, eax |
add esi, 12+1 ; file name length |
call fileread |
jmp file_system_return |
fs_noramdisk_read: |
fs_noramdisk: |
;******************************************************************** |
mov eax, [edi+1] |
cmp eax, 'FD ' |
je fs_yesflpdisk |
cmp eax, 'FLOP' |
jne fs_noflpdisk |
fs_yesflpdisk: |
call reserve_flp |
cmp byte [edi+1+11], 0 |
je fs_give_dir1 |
mov eax, [edi+1+12] |
cmp eax, '1 ' |
je fs_yesflpdisk_first |
cmp eax, 'FIRS' |
je fs_yesflpdisk_first |
cmp eax, '2 ' |
je fs_yesflpdisk_second |
cmp eax, 'SECO' |
jne fs_noflpdisk |
jmp fs_yesflpdisk_second |
fs_yesflpdisk_first: |
mov [flp_number], 1 |
jmp fs_yesflpdisk_start |
fs_yesflpdisk_second: |
mov [flp_number], 2 |
fs_yesflpdisk_start: |
cmp dword [esp+20], 0; READ |
jne fs_noflpdisk_read |
mov eax, [esp+4] ; fname |
add eax, 2*12+1 |
mov ebx, [esp+16] ; block start |
inc ebx |
mov ecx, [esp+12] ; block count |
mov edx, [esp+8] ; return |
mov esi, [esp+0] |
sub esi, eax |
add esi, 12+1 ; file name length |
call floppy_fileread |
jmp file_system_return |
fs_noflpdisk_read: |
fs_noflpdisk: |
;***************************************************************** |
mov eax, [edi+1] |
cmp eax, 'HD0 ' |
je fs_yesharddisk_IDE0 |
cmp eax, 'HD1 ' |
je fs_yesharddisk_IDE1 |
cmp eax, 'HD2 ' |
je fs_yesharddisk_IDE2 |
cmp eax, 'HD3 ' |
je fs_yesharddisk_IDE3 |
jmp old_path_harddisk |
fs_yesharddisk_IDE0: |
call reserve_hd1 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x0 |
mov [hdpos], 1 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE1: |
call reserve_hd1 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x10 |
mov [hdpos], 2 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE2: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0x0 |
mov [hdpos], 3 |
jmp fs_yesharddisk_partition |
fs_yesharddisk_IDE3: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
mov [hdpos], 4 |
fs_yesharddisk_partition: |
call reserve_hd_channel |
; call choice_necessity_partition |
; jmp fs_yesharddisk_all |
jmp fs_for_new_semantic |
choice_necessity_partition: |
mov eax, [edi+1+12] |
call StringToNumber |
mov [fat32part], eax |
choice_necessity_partition_1: |
mov ecx, [hdpos] |
xor eax, eax |
mov [hd_entries], eax; entries in hd cache |
mov edx, DRIVE_DATA+2 |
cmp ecx, 0x80 |
jb search_partition_array |
mov ecx, 4 |
search_partition_array: |
mov bl, [edx] |
movzx ebx, bl |
add eax, ebx |
inc edx |
loop search_partition_array |
mov ecx, [hdpos] |
mov edx, BiosDiskPartitions |
sub ecx, 0x80 |
jb .s |
je .f |
@@: |
mov ebx, [edx] |
add edx, 4 |
add eax, ebx |
loop @b |
jmp .f |
.s: |
sub eax, ebx |
.f: |
add eax, [known_part]; add eax,[fat32part] |
dec eax |
xor edx, edx |
imul eax, 100 |
add eax, DRIVE_DATA+0xa |
mov [transfer_adress], eax |
call partition_data_transfer_1 |
ret |
old_path_harddisk: |
mov eax, [edi+1] |
cmp eax, 'HD ' |
je fs_yesharddisk |
cmp eax, 'HARD' |
jne fs_noharddisk |
fs_yesharddisk: |
cmp dword [esp+20], 8; LBA read |
jne fs_no_LBA_read |
mov eax, [esp+16] ; LBA block to read |
lea ebx, [edi+1+12] ; pointer to FIRST/SECOND/THIRD/FOURTH |
mov ecx, [esp+8] ; abs pointer to return area |
call LBA_read |
jmp file_system_return |
fs_no_LBA_read: |
cmp byte [edi+1+11], 0; directory read |
je fs_give_dir1 |
call reserve_hd1 |
fs_for_new_semantic: |
call choice_necessity_partition |
fs_yesharddisk_all: |
mov eax, 1 |
mov ebx, [esp+24+24] |
cmp [hdpos], 0 ; is hd base set? |
jz hd_err_return |
cmp [fat32part], 0 ; is partition set? |
jnz @f |
hd_err_return: |
call free_hd_channel |
and [hd1_status], 0 |
jmp file_system_return |
@@: |
call free_hd_channel |
and [hd1_status], 0 |
fs_noharddisk: |
; \begin{diamond}[18.03.2006] |
mov eax, 5 ; file not found |
; à ìîæåò áûòü, âîçâðàùàòü äðóãîé êîä îøèáêè? |
mov ebx, [esp+24+24]; do not change ebx in application |
; \end{diamond}[18.03.2006] |
file_system_return: |
add esp, 24 |
mov [esp+36], eax |
mov [esp+24], ebx |
ret |
fs_give_dir1: |
; \begin{diamond}[18.03.2006] |
; /RD,/FD,/HD - only read is allowed |
; other operations return "access denied", eax=10 |
; (execute operation returns eax=-10) |
cmp dword [esp+20], 0 |
jz .read |
add esp, 20 |
pop ecx |
mov dword [esp+36], 10 |
ret |
.read: |
; \end{diamond}[18.03.2006] |
mov al, 0x10 |
mov ebx, 1 |
mov edi, [esp+8] |
mov esi, dir1 |
fs_d1_new: |
mov ecx, 11 |
; cld |
rep movsb |
stosb |
add edi, 32-11-1 |
dec ebx |
jne fs_d1_new |
add esp, 24 |
and dword [esp+36], 0; ok read |
mov dword [esp+24], 32*1; dir/data size |
ret |
LBA_read_ramdisk: |
cmp [lba_read_enabled], 1 |
je lbarrl1 |
xor ebx, ebx |
mov eax, 2 |
ret |
lbarrl1: |
cmp eax, 18*2*80 |
jb lbarrl2 |
xor ebx, ebx |
mov eax, 3 |
ret |
lbarrl2: |
pushad |
call restorefatchain |
mov edi, ecx |
mov esi, eax |
shl esi, 9 |
add esi, RAMDISK |
mov ecx, 512/4 |
; cld |
rep movsd |
popad |
xor ebx, ebx |
xor eax, eax |
ret |
LBA_read: |
; IN: |
; |
; eax = LBA block to read |
; ebx = pointer to FIRST/SECOND/THIRD/FOURTH |
; ecx = abs pointer to return area |
cmp [lba_read_enabled], 1 |
je lbarl1 |
mov eax, 2 |
ret |
lbarl1: |
call reserve_hd1 |
push eax |
push ecx |
mov edi, hd_address_table |
mov esi, dir1 |
mov eax, [ebx] |
mov edx, '1 ' |
mov ecx, 4 |
blar0: |
cmp eax, [esi] |
je blar2 |
cmp eax, edx |
je blar2 |
inc edx |
add edi, 8 |
add esi, 11 |
dec ecx |
jnz blar0 |
mov eax, 1 |
mov ebx, 1 |
jmp LBA_read_ret |
blar2: |
mov eax, [edi+0] |
mov ebx, [edi+4] |
mov [hdbase], eax |
mov [hdid], ebx |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jne hd_lba_error |
; eax = hd port |
; ebx = set for primary (0x00) or slave (0x10) |
cli |
mov edx, eax |
inc edx |
xor eax, eax |
out dx, al |
inc edx |
inc eax |
out dx, al |
inc edx |
mov eax, [esp+4] |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
and al, 1+2+4+8 |
add al, bl |
add al, 128+64+32 |
out dx, al |
inc edx |
mov al, 20h |
out dx, al |
sti |
call wait_for_sector_buffer |
cmp [hd_error], 0 |
jne hd_lba_error |
cli |
mov edi, [esp+0] |
mov ecx, 256 |
sub edx, 7 |
cld |
rep insw |
sti |
xor eax, eax |
xor ebx, ebx |
LBA_read_ret: |
mov [hd_error], 0 |
mov [hd1_status], 0 |
add esp, 2*4 |
ret |
expand_pathz: |
; IN: |
; esi = asciiz path & file |
; edi = buffer for path & file name |
; OUT: |
; edi = directory & file : / 11 + / 11 + / 11 - zero terminated |
; ebx = /file name - zero terminated |
; esi = pointer after source |
push eax |
push ecx |
push edi;[esp+0] |
pathz_start: |
mov byte [edi], '/' |
inc edi |
mov al, 32 |
mov ecx, 11 |
cld |
rep stosb ; clear filename area |
sub edi, 11 |
mov ebx, edi ; start of dir/file name |
pathz_new_char: |
mov al, [esi] |
inc esi |
cmp al, 0 |
je pathz_end |
cmp al, '/' |
jne pathz_not_path |
cmp edi, ebx ; skip first '/' |
jz pathz_new_char |
lea edi, [ebx+11] ; start of next directory |
jmp pathz_start |
pathz_not_path: |
cmp al, '.' |
jne pathz_not_ext |
lea edi, [ebx+8] ; start of extension |
jmp pathz_new_char |
pathz_not_ext: |
cmp al, 'a' |
jb pathz_not_low |
cmp al, 'z' |
ja pathz_not_low |
sub al, 0x20 ; char to uppercase |
pathz_not_low: |
mov [edi], al |
inc edi |
mov eax, [esp+0] ; start_of_dest_path |
add eax, 512 ; keep maximum path under 512 bytes |
cmp edi, eax |
jb pathz_new_char |
pathz_end: |
cmp ebx, edi ; if path end with '/' |
jnz pathz_put_zero ; go back 1 level |
sub ebx, 12 |
pathz_put_zero: |
mov byte [ebx+11], 0 |
dec ebx ; include '/' char into file name |
pop edi |
pop ecx |
pop eax |
ret |
;******************************************* |
;* string to number |
;* input eax - 4 byte string |
;* output eax - number |
;******************************************* |
StringToNumber: |
; ÏÅÐÅÂÎÄ ÑÒÐÎÊÎÂÎÃÎ ×ÈÑËÀ  ×ÈÑËÎÂÎÉ ÂÈÄ |
; Âõîä: |
; EDI - àäðåñ ñòðîêè ñ ÷èñëîì. Êîíåö ÷èñëà îòìå÷åí êîäîì 0Dh |
; Âûõîä: |
; CF - èíäèêàòîð îøèáîê: |
; 0 - îøèáîê íåò; |
; 1 - îøèáêà |
; Åñëè CF=0, òî AX - ÷èñëî. |
push bx |
push cx |
push dx |
push edi |
mov [partition_string], eax |
mov edi, partition_string |
xor cx, cx |
i1: |
mov al, [edi] |
cmp al, 32;13 |
je i_exit |
; cmp al,'0' |
; jb err |
; cmp al,'9' |
; ja err |
sub al, 48 |
shl cx, 1 |
jc error |
mov bx, cx |
shl cx, 1 |
jc error |
shl cx, 1 |
jc error |
add cx, bx |
jc error |
cbw |
add cx, ax |
jc error |
i3: |
inc edi |
jmp i1 |
i_exit: |
mov ax, cx |
clc |
i4: |
movzx eax, ax |
pop edi |
pop dx |
pop cx |
pop bx |
ret |
error: |
stc |
jmp i4 |
partition_string: |
dd 0 |
db 32 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/fs_lfn.inc |
---|
0,0 → 1,1209 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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_FAT_TABLE = 9 ;deprecated |
ERROR_FS_FAIL = 9 |
ERROR_ACCESS_DENIED = 10 |
ERROR_DEVICE = 11 |
; Errors specific to fn.70.7 - program start |
ERROR_MEMORY_NOT_ENOUGH = 30 |
ERROR_INVALID_HEADER = 31 |
ERROR_TOO_MANY_PROCESSES = 32 |
ERROR_WRONG_HEADER_VERSION = 33 ; the version of the header is lower than needed for specific feature. |
image_of_eax EQU esp+32 |
image_of_ebx EQU esp+20 |
struc FileInfoBlock { |
.sub_fn dd ? |
.offset dd ? |
.flags dd ? |
.size dd ? |
.ptr_buff dd ? |
.filename rb 1 |
.pFilename dd ? |
; variants |
label .execFlags dword at .offset |
label .execPtrArg dword at .flags |
label .execStdIO dword at .size |
label .execStdErr dword at .ptr_buff |
} |
virtual at 0 |
FileInfoBlock FileInfoBlock |
end virtual |
; System function 70 - files with long names (LFN) |
; diamond, 2006 |
iglobal |
; in this table names must be in lowercase |
rootdirs: |
db 2,'rd' |
dd fs_OnRamdisk |
dd fs_NextRamdisk |
db 7,'ramdisk' |
dd fs_OnRamdisk |
dd fs_NextRamdisk |
db 2,'fd' |
dd fs_OnFloppy |
dd fs_NextFloppy |
db 10,'floppydisk' |
dd fs_OnFloppy |
dd fs_NextFloppy |
db 3,'hd0' |
dd fs_OnHd0 |
dd fs_NextHd0 |
db 3,'hd1' |
dd fs_OnHd1 |
dd fs_NextHd1 |
db 3,'hd2' |
dd fs_OnHd2 |
dd fs_NextHd2 |
db 3,'hd3' |
dd fs_OnHd3 |
dd fs_NextHd3 |
;********************************************** |
db 3,'cd0' |
dd fs_OnCd0 |
dd fs_NextCd |
db 3,'cd1' |
dd fs_OnCd1 |
dd fs_NextCd |
db 3,'cd2' |
dd fs_OnCd2 |
dd fs_NextCd |
db 3,'cd3' |
dd fs_OnCd3 |
dd fs_NextCd |
;*********************************************** |
db 0 |
virtual_root_query: |
dd fs_HasRamdisk |
db 'rd',0 |
dd fs_HasFloppy |
db 'fd',0 |
dd fs_HasHd0 |
db 'hd0',0 |
dd fs_HasHd1 |
db 'hd1',0 |
dd fs_HasHd2 |
db 'hd2',0 |
dd fs_HasHd3 |
db 'hd3',0 |
;********************************************** |
dd fs_HasCd0 |
db 'cd0',0 |
dd fs_HasCd1 |
db 'cd1',0 |
dd fs_HasCd2 |
db 'cd2',0 |
dd fs_HasCd3 |
db 'cd3',0 |
;********************************************** |
dd 0 |
fs_additional_handlers: |
dd biosdisk_handler, biosdisk_enum_root |
dd dyndisk_handler, dyndisk_enum_root |
; add new handlers here |
dd 0 |
endg |
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 |
file_system_lfn: |
; in: ebx->fileinfo block |
; operation codes: |
; 0 : read file |
; 1 : read folder |
; 2 : create/rewrite file |
; 3 : write/append to file |
; 4 : set end of file |
; 5 : get file/directory attributes structure |
; 6 : set file/directory attributes structure |
; 7 : start application |
; 8 : delete file |
; 9 : create directory |
; parse file name |
lea esi, [ebx+FileInfoBlock.filename] |
lodsb |
test al, al |
jnz @f |
mov esi, [esi] ; FileInfoBlock.pFilename actually. |
lodsb |
@@: |
cmp al, '/' |
jz .notcurdir |
dec esi |
mov ebp, esi |
test al, al |
jnz @f |
xor ebp, ebp |
@@: |
mov esi, [current_slot] |
mov esi, [esi+APPDATA.cur_dir] |
jmp .parse_normal |
.notcurdir: |
cmp byte [esi], 0 |
jz .rootdir |
call process_replace_file_name |
.parse_normal: |
cmp dword [ebx], 7 |
jne .not_execute |
mov eax, [ebx+FileInfoBlock.execStdIO] ; or NULL if not needed. |
mov ecx, [ebx+FileInfoBlock.execStdErr] ; or NULL if not needed. |
mov edx, [ebx+FileInfoBlock.execFlags] ; now only debug flag |
mov ebx, [ebx+FileInfoBlock.execPtrArg] ; pointer to string with command line arguments. |
call fs_execute ; esi+ebp, ebx, edx |
mov [image_of_eax], eax |
ret |
.not_execute: |
mov edi, rootdirs-8 |
xor ecx, ecx |
push esi |
.scan1: |
pop esi |
add edi, ecx |
scasd |
scasd |
mov cl, byte [edi] |
test cl, cl |
jz .notfound_try |
inc edi |
push esi |
@@: |
lodsb |
or al, 20h |
scasb |
loopz @b |
jnz .scan1 |
lodsb |
cmp al, '/' |
jz .found1 |
test al, al |
jnz .scan1 |
pop eax |
; directory /xxx |
.maindir: |
mov esi, [edi+4] |
.maindir_noesi: |
cmp dword [ebx], 1 |
jnz .access_denied |
xor eax, eax |
mov ebp, [ebx+12] ; block count to be read. |
mov edx, [ebx+16] ; where to write the result. |
; add edx, std_application_base_address |
push dword [ebx+4] ; first block |
mov ebx, [ebx+8] ; flags |
; ebx=flags, [esp]=first block, ebp=number of blocks, edx=return area, esi='Next' handler |
mov edi, edx |
push ecx |
mov ecx, 32/4 |
rep stosd |
pop ecx |
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], 0x10 ; attributes: folder |
mov dword [edi+4], 1 ; name type: UNICODE |
push eax |
xor eax, eax |
add edi, 8 |
push ecx |
mov ecx, 40/4-2 |
rep stosd |
pop ecx |
pop eax |
push eax edx |
; convert number in eax to decimal UNICODE string |
push edi |
push ecx |
push -'0' |
mov ecx, 10 |
@@: |
xor edx, edx |
div ecx |
push edx |
test eax, eax |
jnz @b |
@@: |
pop eax |
add al, '0' |
stosb |
test bl, 1 ; UNICODE name? |
jz .ansi2 |
mov byte [edi], 0 |
inc edi |
.ansi2: |
test al, al |
jnz @b |
mov byte [edi-1], 0 |
pop ecx |
pop edi |
; UNICODE name length is 520 bytes, ANSI - 264 |
add edi, 520 |
test bl, 1 |
jnz @f |
sub edi, 520-264 |
@@: |
pop edx eax |
jmp .maindir_loop |
.maindir_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 |
; directory / |
.rootdir: |
cmp dword [ebx], 1 ; read folder? |
jz .readroot |
.access_denied: |
mov dword [image_of_eax], 10 ; access denied |
ret |
.readroot: |
; virtual root folder - special handler |
mov esi, virtual_root_query |
mov ebp, [ebx+12] |
mov edx, [ebx+16] |
; add edx, std_application_base_address |
push dword [ebx+4] ; first block |
mov ebx, [ebx+8] ; flags |
xor eax, eax |
; eax=0, [esp]=first block, ebx=flags, ebp=number of blocks, edx=return area |
mov edi, edx |
mov ecx, 32/4 |
rep stosd |
mov byte [edx], 1 ; version |
.readroot_loop: |
cmp dword [esi], eax |
jz .readroot_done_static |
call dword [esi] |
add esi, 4 |
test eax, eax |
jnz @f |
.readroot_next: |
or ecx, -1 |
xchg esi, edi |
repnz scasb |
xchg esi, edi |
jmp .readroot_loop |
@@: |
xor eax, eax |
inc dword [edx+8] |
dec dword [esp] |
jns .readroot_next |
dec ebp |
js .readroot_next |
inc dword [edx+4] |
mov dword [edi], 0x10 ; attributes: folder |
mov dword [edi+4], ebx ; name type: UNICODE |
add edi, 8 |
mov ecx, 40/4-2 |
rep stosd |
push edi |
@@: |
lodsb |
stosb |
test bl, 1 |
jz .ansi |
mov byte [edi], 0 |
inc edi |
.ansi: |
test eax, eax |
jnz @b |
pop edi |
add edi, 520 |
test bl, 1 |
jnz .readroot_loop |
sub edi, 520-264 |
jmp .readroot_loop |
.readroot_done_static: |
mov esi, fs_additional_handlers-8 |
sub esp, 16 |
.readroot_ah_loop: |
add esi, 8 |
cmp dword [esi], 0 |
jz .readroot_done |
xor eax, eax |
.readroot_ah_loop2: |
push edi |
lea edi, [esp+4] |
call dword [esi+4] |
pop edi |
test eax, eax |
jz .readroot_ah_loop |
inc dword [edx+8] |
dec dword [esp+16] |
jns .readroot_ah_loop2 |
dec ebp |
js .readroot_ah_loop2 |
push eax |
xor eax, eax |
inc dword [edx+4] |
mov dword [edi], 0x10 ; attributes: folder |
mov dword [edi+4], ebx |
add edi, 8 |
mov ecx, 40/4-2 |
rep stosd |
push esi edi |
lea esi, [esp+12] |
@@: |
lodsb |
stosb |
test bl, 1 |
jz .ansi3 |
mov byte [edi], 0 |
inc edi |
.ansi3: |
test al, al |
jnz @b |
pop edi esi eax |
add edi, 520 |
test bl, 1 |
jnz .readroot_ah_loop2 |
sub edi, 520-264 |
jmp .readroot_ah_loop2 |
.readroot_done: |
add esp, 16 |
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 |
.notfound_try: |
mov edi, fs_additional_handlers |
@@: |
cmp dword [edi], 0 |
jz .notfound |
call dword [edi] |
scasd |
scasd |
jmp @b |
.notfound: |
mov dword [image_of_eax], ERROR_FILE_NOT_FOUND |
and dword [image_of_ebx], 0 |
ret |
.notfounda: |
cmp edi, esp |
jnz .notfound |
call dword [edi+4] |
add esp, 16 |
jmp .notfound |
.found1: |
pop eax |
cmp byte [esi], 0 |
jz .maindir |
.found2: |
; read partition number |
xor ecx, ecx |
xor eax, eax |
@@: |
lodsb |
cmp al, '/' |
jz .done1 |
test al, al |
jz .done1 |
sub al, '0' |
cmp al, 9 |
ja .notfounda |
lea ecx, [ecx*5] |
lea ecx, [ecx*2+eax] |
jmp @b |
.done1: |
jecxz .notfounda |
test al, al |
jnz @f |
dec esi |
@@: |
cmp byte [esi], 0 |
jnz @f |
test ebp, ebp |
jz @f |
mov esi, ebp |
xor ebp, ebp |
@@: |
; now [edi] contains handler address, ecx - partition number, |
; esi points to ASCIIZ string - rest of name |
jmp dword [edi] |
; handlers for devices |
; in: ecx = 0 => query virtual directory /xxx |
; in: ecx = partition number |
; esi -> relative (for device) name |
; ebx -> fileinfo |
; ebp = 0 or pointer to rest of name from folder addressed by esi |
; out: [image_of_eax]=image of eax, [image_of_ebx]=image of ebx |
fs_OnRamdisk: |
cmp ecx, 1 |
jnz file_system_lfn.notfound |
mov eax, [ebx] |
cmp eax, fs_NumRamdiskServices |
jae .not_impl |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
; add edx, std_application_base_address |
add ebx, 4 |
call dword [fs_RamdiskServices + eax*4] |
mov [image_of_eax], eax |
mov [image_of_ebx], ebx |
ret |
.not_impl: |
mov dword [image_of_eax], 2 ; not implemented |
ret |
fs_NotImplemented: |
mov eax, 2 |
ret |
fs_RamdiskServices: |
dd fs_RamdiskRead |
dd fs_RamdiskReadFolder |
dd fs_RamdiskRewrite |
dd fs_RamdiskWrite |
dd fs_RamdiskSetFileEnd |
dd fs_RamdiskGetFileInfo |
dd fs_RamdiskSetFileInfo |
dd 0 |
dd fs_RamdiskDelete |
dd fs_RamdiskCreateFolder |
fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4 |
fs_OnFloppy: |
cmp ecx, 2 |
ja file_system_lfn.notfound |
mov eax, [ebx] |
cmp eax, fs_NumFloppyServices |
jae fs_OnRamdisk.not_impl |
call reserve_flp |
mov [flp_number], cl |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
; add edx, std_application_base_address |
add ebx, 4 |
call dword [fs_FloppyServices + eax*4] |
and [flp_status], 0 |
mov [image_of_eax], eax |
mov [image_of_ebx], ebx |
ret |
fs_FloppyServices: |
dd fs_FloppyRead |
dd fs_FloppyReadFolder |
dd fs_FloppyRewrite |
dd fs_FloppyWrite |
dd fs_FloppySetFileEnd |
dd fs_FloppyGetFileInfo |
dd fs_FloppySetFileInfo |
dd 0 |
dd fs_FloppyDelete |
dd fs_FloppyCreateFolder |
fs_NumFloppyServices = ($ - fs_FloppyServices)/4 |
fs_OnHd0: |
call reserve_hd1 |
mov [hdbase], 0x1F0 |
mov [hdid], 0 |
push 1 |
jmp fs_OnHd |
fs_OnHd1: |
call reserve_hd1 |
mov [hdbase], 0x1F0 |
mov [hdid], 0x10 |
push 2 |
jmp fs_OnHd |
fs_OnHd2: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0 |
push 3 |
jmp fs_OnHd |
fs_OnHd3: |
call reserve_hd1 |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
push 4 |
fs_OnHd: |
call reserve_hd_channel |
pop eax |
mov [hdpos], eax |
cmp ecx, 0x100 |
jae fs_OnHdAndBd.nf |
cmp cl, [DRIVE_DATA+1+eax] |
fs_OnHdAndBd: |
jbe @f |
.nf: |
call free_hd_channel |
and [hd1_status], 0 |
mov dword [image_of_eax], 5 ; not found |
ret |
@@: |
mov [known_part], ecx ; mov [fat32part], ecx |
push ebx esi |
call choice_necessity_partition_1 |
pop esi ebx |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
; add edx, std_application_base_address |
mov eax, [ebx] |
cmp eax, fs_NumHdServices |
jae .not_impl |
add ebx, 4 |
call dword [fs_HdServices + eax*4] |
call free_hd_channel |
and [hd1_status], 0 |
mov [image_of_eax], eax |
mov [image_of_ebx], ebx |
ret |
.not_impl: |
call free_hd_channel |
and [hd1_status], 0 |
mov dword [image_of_eax], 2 ; not implemented |
ret |
fs_HdServices: |
dd fs_HdRead |
dd fs_HdReadFolder |
dd fs_HdRewrite |
dd fs_HdWrite |
dd fs_HdSetFileEnd |
dd fs_HdGetFileInfo |
dd fs_HdSetFileInfo |
dd 0 |
dd fs_HdDelete |
dd fs_HdCreateFolder |
fs_NumHdServices = ($ - fs_HdServices)/4 |
;******************************************************* |
fs_OnCd0: |
call reserve_cd |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
push 6 |
push 1 |
jmp fs_OnCd |
fs_OnCd1: |
call reserve_cd |
mov [ChannelNumber], 1 |
mov [DiskNumber], 1 |
push 4 |
push 2 |
jmp fs_OnCd |
fs_OnCd2: |
call reserve_cd |
mov [ChannelNumber], 2 |
mov [DiskNumber], 0 |
push 2 |
push 3 |
jmp fs_OnCd |
fs_OnCd3: |
call reserve_cd |
mov [ChannelNumber], 2 |
mov [DiskNumber], 1 |
push 0 |
push 4 |
fs_OnCd: |
call reserve_cd_channel |
pop eax |
mov [cdpos], eax |
pop eax |
cmp ecx, 0x100 |
jae .nf |
push ecx ebx |
mov cl, al |
mov bl, [DRIVE_DATA+1] |
shr bl, cl |
test bl, 2 |
pop ebx ecx |
jnz @f |
.nf: |
call free_cd_channel |
and [cd_status], 0 |
mov dword [image_of_eax], 5 ; not found |
ret |
@@: |
mov ecx, [ebx+12] |
mov edx, [ebx+16] |
; add edx, std_application_base_address |
mov eax, [ebx] |
cmp eax, fs_NumCdServices |
jae .not_impl |
add ebx, 4 |
call dword [fs_CdServices + eax*4] |
call free_cd_channel |
and [cd_status], 0 |
mov [image_of_eax], eax |
mov [image_of_ebx], ebx |
ret |
.not_impl: |
call free_cd_channel |
and [cd_status], 0 |
mov dword [image_of_eax], 2 ; not implemented |
ret |
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 |
;******************************************************* |
fs_HasRamdisk: |
mov al, 1 ; we always have ramdisk |
ret |
fs_HasFloppy: |
cmp byte [DRIVE_DATA], 0 |
setnz al |
ret |
fs_HasHd0: |
mov al, [DRIVE_DATA+1] |
and al, 11000000b |
cmp al, 01000000b |
setz al |
ret |
fs_HasHd1: |
mov al, [DRIVE_DATA+1] |
and al, 00110000b |
cmp al, 00010000b |
setz al |
ret |
fs_HasHd2: |
mov al, [DRIVE_DATA+1] |
and al, 00001100b |
cmp al, 00000100b |
setz al |
ret |
fs_HasHd3: |
mov al, [DRIVE_DATA+1] |
and al, 00000011b |
cmp al, 00000001b |
setz al |
ret |
;******************************************************* |
fs_HasCd0: |
mov al, [DRIVE_DATA+1] |
and al, 11000000b |
cmp al, 10000000b |
setz al |
ret |
fs_HasCd1: |
mov al, [DRIVE_DATA+1] |
and al, 00110000b |
cmp al, 00100000b |
setz al |
ret |
fs_HasCd2: |
mov al, [DRIVE_DATA+1] |
and al, 00001100b |
cmp al, 00001000b |
setz al |
ret |
fs_HasCd3: |
mov al, [DRIVE_DATA+1] |
and al, 00000011b |
cmp al, 00000010b |
setz al |
ret |
;******************************************************* |
; fs_NextXXX functions: |
; in: eax = partition number, from which start to scan |
; out: CF=1 => no more partitions |
; CF=0 => eax=next partition number |
fs_NextRamdisk: |
; we always have /rd/1 |
test eax, eax |
stc |
jnz @f |
mov al, 1 |
clc |
@@: |
ret |
fs_NextFloppy: |
; we have /fd/1 iff (([DRIVE_DATA] and 0xF0) != 0) and /fd/2 iff (([DRIVE_DATA] and 0x0F) != 0) |
test byte [DRIVE_DATA], 0xF0 |
jz .no1 |
test eax, eax |
jnz .no1 |
inc eax |
ret ; CF cleared |
.no1: |
test byte [DRIVE_DATA], 0x0F |
jz .no2 |
cmp al, 2 |
jae .no2 |
mov al, 2 |
clc |
ret |
.no2: |
stc |
ret |
; on hdx, we have partitions from 1 to [0x40002+x] |
fs_NextHd0: |
push 0 |
jmp fs_NextHd |
fs_NextHd1: |
push 1 |
jmp fs_NextHd |
fs_NextHd2: |
push 2 |
jmp fs_NextHd |
fs_NextHd3: |
push 3 |
fs_NextHd: |
pop ecx |
movzx ecx, byte [DRIVE_DATA+2+ecx] |
cmp eax, ecx |
jae fs_NextFloppy.no2 |
inc eax |
clc |
ret |
;******************************************************* |
fs_NextCd: |
; we always have /cdX/1 |
test eax, eax |
stc |
jnz @f |
mov al, 1 |
clc |
@@: |
ret |
;******************************************************* |
; Additional FS handlers. |
; This handler gets the control each time when fn 70 is called |
; with unknown item of root subdirectory. |
; in: esi -> name |
; ebp = 0 or rest of name relative to esi |
; out: if the handler processes path, he must not return in file_system_lfn, |
; but instead pop return address and return directly to the caller |
; otherwise simply return |
; here we test for /bd<N>/... - BIOS disks |
biosdisk_handler: |
cmp [NumBiosDisks], 0 |
jz .ret |
mov al, [esi] |
or al, 20h |
cmp al, 'b' |
jnz .ret |
mov al, [esi+1] |
or al, 20h |
cmp al, 'd' |
jnz .ret |
push esi |
inc esi |
inc esi |
cmp byte [esi], '0' |
jb .ret2 |
cmp byte [esi], '9' |
ja .ret2 |
xor edx, edx |
@@: |
lodsb |
test al, al |
jz .ok |
cmp al, '/' |
jz .ok |
sub al, '0' |
cmp al, 9 |
ja .ret2 |
lea edx, [edx*5] |
lea edx, [edx*2+eax] |
jmp @b |
.ret2: |
pop esi |
.ret: |
ret |
.ok: |
cmp al, '/' |
jz @f |
dec esi |
@@: |
add dl, 80h |
xor ecx, ecx |
@@: |
cmp dl, [BiosDisksData+ecx*4] |
jz .ok2 |
inc ecx |
cmp ecx, [NumBiosDisks] |
jb @b |
jmp .ret2 |
.ok2: |
add esp, 8 |
test al, al |
jnz @f |
mov esi, fs_BdNext |
jmp file_system_lfn.maindir_noesi |
@@: |
push ecx |
push ecx |
push biosdisk_cleanup |
push fs_OnBd |
mov edi, esp |
jmp file_system_lfn.found2 |
fs_BdNext: |
cmp eax, [BiosDiskPartitions+ecx*4] |
inc eax |
cmc |
biosdisk_cleanup: |
ret |
fs_OnBd: |
pop edx edx edx edx |
; edx = disk number, ecx = partition number |
; esi+ebp = name |
call reserve_hd1 |
add edx, 0x80 |
mov [hdpos], edx |
cmp ecx, [BiosDiskPartitions+(edx-0x80)*4] |
jmp fs_OnHdAndBd |
; 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 |
; here we enumerate existing BIOS disks /bd<N> |
biosdisk_enum_root: |
cmp eax, [NumBiosDisks] |
jae .end |
push eax |
movzx eax, byte [BiosDisksData+eax*4] |
sub al, 80h |
push eax |
mov al, 'b' |
stosb |
mov al, 'd' |
stosb |
pop eax |
cmp al, 10 |
jae .big |
add al, '0' |
stosb |
mov byte [edi], 0 |
pop eax |
inc eax |
ret |
.end: |
xor eax, eax |
ret |
.big: |
push ecx edx |
push -'0' |
mov ecx, 10 |
@@: |
xor edx, edx |
div ecx |
push edx |
test eax, eax |
jnz @b |
xchg eax, edx |
@@: |
pop eax |
add al, '0' |
stosb |
jnz @b |
pop edx ecx |
pop eax |
inc eax |
ret |
process_replace_file_name: |
mov ebp, [full_file_name_table] |
mov edi, [full_file_name_table.size] |
dec edi |
shl edi, 7 |
add edi, ebp |
.loop: |
cmp edi, ebp |
jb .notfound |
push esi edi |
@@: |
cmp byte [edi], 0 |
jz .dest_done |
lodsb |
test al, al |
jz .cont |
or al, 20h |
scasb |
jz @b |
jmp .cont |
.dest_done: |
cmp byte [esi], 0 |
jz .found |
cmp byte [esi], '/' |
jnz .cont |
inc esi |
jmp .found |
.cont: |
pop edi esi |
sub edi, 128 |
jmp .loop |
.found: |
pop edi eax |
mov ebp, esi |
cmp byte [esi], 0 |
lea esi, [edi+64] |
jnz .ret |
.notfound: |
xor ebp, ebp |
.ret: |
ret |
sys_current_directory: |
; mov esi, [current_slot] |
; mov esi, [esi+APPDATA.cur_dir] |
; mov edx, esi |
;get length string of appdata.cur_dir |
mov eax, [current_slot] |
mov edi, [eax+APPDATA.cur_dir] |
dec ebx |
jz .set |
dec ebx |
jz .get |
ret |
.get: |
; sysfunction 30.2: [for app] eax=30,ebx=2,ecx->buffer,edx=len |
; for our code: ebx->buffer,ecx=len |
max_cur_dir equ 0x1000 |
mov ebx, edi |
push ecx |
push edi |
xor eax, eax |
mov ecx, max_cur_dir |
repne scasb ;find zerro at and string |
jnz .error ; no zero in cur_dir: internal error, should not happen |
sub edi, ebx ;lenght for copy |
inc edi |
mov [esp+32+8], edi ;return in eax |
cmp edx, edi |
jbe @f |
mov edx, edi |
@@: |
;source string |
pop esi |
;destination string |
pop edi |
cmp edx, 1 |
jbe .ret |
mov al, '/' ;start string with '/' |
stosb |
mov ecx, edx |
rep movsb ;copy string |
.ret: |
ret |
.error: |
add esp, 8 |
or dword [esp+32], -1 ;error not found zerro at string ->[eax+APPDATA.cur_dir] |
ret |
.set: |
; sysfunction 30.1: [for app] eax=30,ebx=1,ecx->string |
; for our code: ebx->string to set |
; use generic resolver with APPDATA.cur_dir as destination |
push max_cur_dir ;0x1000 |
push edi ;destination |
mov ebx, ecx |
call get_full_file_name |
ret |
; in: ebx = file name, [esp+4] = destination, [esp+8] = sizeof destination |
; destroys all registers except ebp,esp |
get_full_file_name: |
push ebp |
mov esi, [current_slot] |
mov esi, [esi+APPDATA.cur_dir] |
mov edx, esi |
@@: |
inc esi |
cmp byte [esi-1], 0 |
jnz @b |
dec esi |
cmp byte [ebx], '/' |
jz .set_absolute |
; string gives relative path |
mov edi, [esp+8] ; destination |
.relative: |
cmp byte [ebx], 0 |
jz .set_ok |
cmp word [ebx], '.' |
jz .set_ok |
cmp word [ebx], './' |
jnz @f |
add ebx, 2 |
jmp .relative |
@@: |
cmp word [ebx], '..' |
jnz .doset_relative |
cmp byte [ebx+2], 0 |
jz @f |
cmp byte [ebx+2], '/' |
jnz .doset_relative |
@@: |
dec esi |
cmp byte [esi], '/' |
jnz @b |
add ebx, 3 |
jmp .relative |
.set_ok: |
cmp edx, edi ; is destination equal to APPDATA.cur_dir? |
jz .set_ok.cur_dir |
sub esi, edx |
cmp esi, [esp+12] |
jb .set_ok.copy |
.fail: |
mov byte [edi], 0 |
xor eax, eax ; fail |
pop ebp |
ret 8 |
.set_ok.copy: |
mov ecx, esi |
mov esi, edx |
rep movsb |
mov byte [edi], 0 |
.ret.ok: |
mov al, 1 ; ok |
pop ebp |
ret 8 |
.set_ok.cur_dir: |
mov byte [esi], 0 |
jmp .ret.ok |
.doset_relative: |
cmp edx, edi |
jz .doset_relative.cur_dir |
sub esi, edx |
cmp esi, [esp+12] |
jae .fail |
mov ecx, esi |
mov esi, edx |
mov edx, edi |
rep movsb |
jmp .doset_relative.copy |
.doset_relative.cur_dir: |
mov edi, esi |
.doset_relative.copy: |
add edx, [esp+12] |
mov byte [edi], '/' |
inc edi |
cmp edi, edx |
jae .overflow |
@@: |
mov al, [ebx] |
inc ebx |
stosb |
test al, al |
jz .ret.ok |
cmp edi, edx |
jb @b |
.overflow: |
dec edi |
jmp .fail |
.set_absolute: |
lea esi, [ebx+1] |
call process_replace_file_name |
mov edi, [esp+8] |
mov edx, [esp+12] |
add edx, edi |
.set_copy: |
lodsb |
stosb |
test al, al |
jz .set_part2 |
.set_copy_cont: |
cmp edi, edx |
jb .set_copy |
jmp .overflow |
.set_part2: |
mov esi, ebp |
xor ebp, ebp |
test esi, esi |
jz .ret.ok |
mov byte [edi-1], '/' |
jmp .set_copy_cont |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/part_set.inc |
---|
0,0 → 1,436 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;************************************************************* |
;* 13.02.2010 Find all partition and check supported FS |
;* 12.07.2007 Check all 4 entry of MBR and EMBR |
;* 29.04.2006 Elimination of hangup after the |
;* expiration hd_wait_timeout - Mario79 |
;* 28.01.2006 find all Fat16/32 partition in all input point |
;* to MBR - Mario79 |
;************************************************************* |
uglobal |
align 4 |
;****************************************************** |
; Please do not change this place - variables in text |
; Mario79 |
; START place |
;****************************************************** |
PARTITION_START dd 0x3f |
PARTITION_END dd 0 |
fs_type db 0 ; 1=NTFS, 2=EXT2/3, 16=FAT16, 32=FAT32 |
align 4 |
fs_dependent_data_start: |
; FATxx data |
.partition dd ? |
rb 80 |
fs_dependent_data_end: |
file_system_data_size = $ - PARTITION_START |
if file_system_data_size > 96 |
ERROR: |
sizeof(file system data) too big! |
end if |
virtual at fs_dependent_data_start |
; NTFS data |
ntfs_data: |
.sectors_per_cluster dd ? |
.mft_cluster dd ? |
.mftmirr_cluster dd ? |
.frs_size dd ? ; FRS size in bytes |
.iab_size dd ? ; IndexAllocationBuffer size in bytes |
.frs_buffer dd ? |
.iab_buffer dd ? |
.mft_retrieval dd ? |
.mft_retrieval_size dd ? |
.mft_retrieval_alloc dd ? |
.mft_retrieval_end dd ? |
.cur_index_size dd ? |
.cur_index_buf dd ? |
if $ > fs_dependent_data_end |
ERROR: |
increase sizeof(fs_dependent_data)! |
end if |
end virtual |
virtual at fs_dependent_data_start |
; EXT2 data |
ext2_data: |
.log_block_size dd ? |
.block_size dd ? |
.count_block_in_block dd ? |
.blocks_per_group dd ? |
.global_desc_table dd ? |
.root_inode dd ? ; pointer to root inode in memory |
.inode_size dd ? |
.count_pointer_in_block dd ? ; block_size / 4 |
.count_pointer_in_block_square dd ? ; (block_size / 4)**2 |
.ext2_save_block dd ? ; ¡«®ª £«®¡ «ìãî 1 ¯à®æ¥¤ãàã |
.ext2_temp_block dd ? ; ¡«®ª ¤«ï ¬¥«ª¨å ¯à®æ¥¤ãà |
.ext2_save_inode dd ? ; inode £«®¡ «ìãî ¯à®æ¥¤ãàã |
.ext2_temp_inode dd ? ; inode ¤«ï ¬¥«ª¨å ¯à®æ¥¤ãà |
.sb dd ? ; superblock |
.groups_count dd ? |
if $ > fs_dependent_data_end |
ERROR: |
increase sizeof(fs_dependent_data)! |
end if |
end virtual |
;*************************************************************************** |
; End place |
; Mario79 |
;*************************************************************************** |
endg |
iglobal |
partition_types: ; list of fat16/32 partitions |
db 0x04 ; DOS: fat16 <32M |
db 0x06 ; DOS: fat16 >32M |
db 0x0b ; WIN95: fat32 |
db 0x0c ; WIN95: fat32, LBA-mapped |
db 0x0e ; WIN95: fat16, LBA-mapped |
db 0x14 ; Hidden DOS: fat16 <32M |
db 0x16 ; Hidden DOS: fat16 >32M |
db 0x1b ; Hidden WIN95: fat32 |
db 0x1c ; Hidden WIN95: fat32, LBA-mapped |
db 0x1e ; Hidden WIN95: fat16, LBA-mapped |
db 0xc4 ; DRDOS/secured: fat16 <32M |
db 0xc6 ; DRDOS/secured: fat16 >32M |
db 0xcb ; DRDOS/secured: fat32 |
db 0xcc ; DRDOS/secured: fat32, LBA-mapped |
db 0xce ; DRDOS/secured: fat16, LBA-mapped |
db 0xd4 ; Old Multiuser DOS secured: fat16 <32M |
db 0xd6 ; Old Multiuser DOS secured: fat16 >32M |
db 0x07 ; NTFS |
db 0x27 ; NTFS, hidden |
db 0x83 ; Linux native file system (ext2fs) |
partition_types_end: |
extended_types: ; list of extended partitions |
db 0x05 ; DOS: extended partition |
db 0x0f ; WIN95: extended partition, LBA-mapped |
db 0xc5 ; DRDOS/secured: extended partition |
db 0xd5 ; Old Multiuser DOS secured: extended partition |
extended_types_end: |
endg |
; Partition chain used: |
; MBR <--------------------- |
; | | |
; |-> PARTITION1 | |
; |-> EXTENDED PARTITION - ;not need be second partition |
; |-> PARTITION3 |
; |-> PARTITION4 |
set_PARTITION_variables: |
set_FAT32_variables: ;deprecated |
and [problem_partition], 0 |
call reserve_hd1 |
call reserve_hd_channel |
pushad |
cmp dword [hdpos], 0 |
je problem_hd |
xor ecx, ecx ; partition count |
;or edx,-1 ; flag for partition |
xor eax, eax ; address MBR |
xor ebp, ebp ; extended partition start |
new_mbr: |
test ebp, ebp ; is there extended partition? (MBR or EMBR) |
jnz extended_already_set; yes |
xchg ebp, eax ; no. set it now |
extended_already_set: |
add eax, ebp ; mbr=mbr+0, ext_part=ext_start+relat_start |
mov ebx, buffer |
call hd_read |
cmp [hd_error], 0 |
jne problem_hd |
cmp word [ebx+0x1fe], 0xaa55; is it valid boot sector? |
jnz end_partition_chain |
push eax ; push only one time |
cmp dword [ebx+0x1be+0xc], 0; skip over empty partition |
jnz test_primary_partition_0 |
cmp dword [ebx+0x1be+0xc+16], 0 |
jnz test_primary_partition_1 |
cmp dword [ebx+0x1be+0xc+16+16], 0 |
jnz test_primary_partition_2 |
cmp dword [ebx+0x1be+0xc+16+16+16], 0 |
jnz test_primary_partition_3 |
pop eax |
jmp end_partition_chain |
test_primary_partition_0: |
mov al, [ebx+0x1be+4]; get primary partition type |
call scan_partition_types |
jnz test_primary_partition_1; no. skip over |
inc ecx |
cmp ecx, [known_part]; is it wanted partition? |
jnz test_primary_partition_1; no |
pop eax |
;mov edx, eax ; start sector |
add eax, [ebx+0x1be+8] ; add relative start |
;mov [PARTITON_START],edx |
;push edx |
mov edx, [ebx+0x1be+12] ; length |
;add edx, eax ; add length |
;dec edx ; PARTITION_END is inclusive |
;mov [PARTITION_END], edx ; note that this can be changed |
; when file system data will be available |
mov cl, [ebx+0x1be+4] ; fs_type |
;mov [fs_type], dl ; save for FS recognizer (separate FAT vs NTFS) |
;pop edx |
jmp hd_and_partition_ok |
test_primary_partition_1: |
mov al, [ebx+0x1be+4+16]; get primary partition type |
call scan_partition_types |
jnz test_primary_partition_2 ; no. skip over |
inc ecx |
cmp ecx, [known_part]; is it wanted partition? |
jnz test_primary_partition_2 ; no |
pop eax |
add eax, [ebx+0x1be+8+16] |
mov edx, [ebx+0x1be+12+16] |
mov cl, [ebx+0x1be+4+16] |
jmp hd_and_partition_ok |
;mov edx, eax |
;add edx, [ebx+0x1be+8+16] |
;push edx |
;add edx, [ebx+0x1be+12+16] |
;dec edx |
;mov [PARTITION_END], edx |
;mov al, [ebx+0x1be+4+16] |
;mov [fs_type], dl |
;pop edx |
test_primary_partition_2: |
mov al, [ebx+0x1be+4+16+16]; get primary partition type |
call scan_partition_types |
jnz test_primary_partition_3 ; no. skip over |
inc ecx |
cmp ecx, [known_part]; is it wanted partition? |
jnz test_primary_partition_3 ; no |
pop eax |
add eax, [ebx+0x1be+8+16+16] |
mov edx, [ebx+0x1be+12+16+16] |
mov cl, [ebx+0x1be+4+16+16] |
jmp hd_and_partition_ok |
;mov edx, eax |
;add edx, [ebx+0x1be+8+16+16] |
;push edx |
;add edx, [ebx+0x1be+12+16+16] |
;dec edx |
;mov [PARTITION_END], edx |
;mov al, [ebx+0x1be+4+16+16] |
;mov [fs_type], dl |
;pop edx |
test_primary_partition_3: |
mov al, [ebx+0x1be+4+16+16+16]; get primary partition type |
call scan_partition_types |
jnz test_ext_partition_0 ; no. skip over |
inc ecx |
cmp ecx, [known_part]; is it wanted partition? |
jnz test_ext_partition_0; no |
pop eax |
add eax, [ebx+0x1be+8+16+16+16] |
mov edx, [ebx+0x1be+12+16+16+16] |
mov cl, [ebx+0x1be+4+16+16+16] |
jmp hd_and_partition_ok |
;mov edx, eax |
;add edx, [ebx+0x1be+8+16+16+16] |
;push edx |
;add edx, [ebx+0x1be+12+16+16+16] |
;dec edx |
;mov [PARTITION_END], edx |
;mov al, [ebx+0x1be+4+16+16+16] |
;mov [fs_type], dl |
;pop edx |
test_ext_partition_0: |
pop eax ; ¯à®áâ® ¢ëª¨¤ë¢ ¥¬ ¨§ á⥪ |
mov al, [ebx+0x1be+4]; get extended partition type |
call scan_extended_types |
jnz test_ext_partition_1 |
mov eax, [ebx+0x1be+8]; add relative start |
test eax, eax ; is there extended partition? |
jnz new_mbr ; yes. read it |
test_ext_partition_1: |
mov al, [ebx+0x1be+4+16]; get extended partition type |
call scan_extended_types |
jnz test_ext_partition_2 |
mov eax, [ebx+0x1be+8+16]; add relative start |
test eax, eax ; is there extended partition? |
jnz new_mbr ; yes. read it |
test_ext_partition_2: |
mov al, [ebx+0x1be+4+16+16]; get extended partition type |
call scan_extended_types |
jnz test_ext_partition_3 |
mov eax, [ebx+0x1be+8+16+16]; add relative start |
test eax, eax ; is there extended partition? |
jnz new_mbr ; yes. read it |
test_ext_partition_3: |
mov al, [ebx+0x1be+4+16+16+16]; get extended partition type |
call scan_extended_types |
jnz end_partition_chain; no. end chain |
mov eax, [ebx+0x1be+8+16+16+16]; get start of extended partition |
test eax, eax ; is there extended partition? |
jnz new_mbr ; yes. read it |
end_partition_chain: |
;mov [partition_count],ecx |
;cmp edx,-1 ; found wanted partition? |
;jnz hd_and_partition_ok ; yes. install it |
;jmp problem_partition_or_fat |
problem_hd: |
or [problem_partition], 2 |
jmp return_from_part_set |
scan_partition_types: |
push ecx |
mov edi, partition_types |
mov ecx, partition_types_end-partition_types |
cld |
repne scasb ; is partition type ok? |
pop ecx |
ret |
scan_extended_types: |
push ecx |
mov edi, extended_types |
mov ecx, extended_types_end-extended_types |
cld |
repne scasb ; is it extended partition? |
pop ecx |
ret |
problem_fat_dec_count: ; bootsector is missing or another problem |
; dec [partition_count] ; remove it from partition_count |
problem_partition_or_fat: |
or [problem_partition], 1 |
return_from_part_set: |
popad |
;mov [fs_type],0 |
call free_hd_channel |
mov [hd1_status], 0 ; free |
ret |
hd_and_partition_ok: |
;eax = PARTITION_START edx=PARTITION_LENGTH cl=fs_type |
mov [fs_type], cl |
;mov eax,edx |
mov [PARTITION_START], eax |
add edx, eax |
dec edx |
mov [PARTITION_END], edx |
; mov edx, [PARTITION_END] |
; sub edx, eax |
; inc edx ; edx = length of partition § 祬 ®® ¬?? |
; mov [hd_setup],1 |
mov ebx, buffer |
call hd_read ; read boot sector of partition |
cmp [hd_error], 0 |
jz boot_read_ok |
cmp [fs_type], 7 |
jnz problem_fat_dec_count |
; NTFS duplicates bootsector: |
; NT4/2k/XP+ saves bootsector copy in the end of disk |
; NT 3.51 saves bootsector copy in the middle of disk |
and [hd_error], 0 |
mov eax, [PARTITION_END] |
call hd_read |
cmp [hd_error], 0 |
jnz @f |
call ntfs_test_bootsec |
jnc boot_read_ok |
@@: |
and [hd_error], 0 |
mov eax, edx |
shr eax, 1 |
add eax, [PARTITION_START] |
call hd_read |
cmp [hd_error], 0 |
jnz problem_fat_dec_count ; no chance... |
boot_read_ok: |
; if we are running on NTFS, check bootsector |
call ntfs_test_bootsec ; test ntfs |
jnc ntfs_setup |
call ext2_test_superblock ; test ext2fs |
jnc ext2_setup |
mov eax, [PARTITION_START] ;ext2 test changes [buffer] |
call hd_read |
cmp [hd_error], 0 |
jnz problem_fat_dec_count |
push 0 |
mov eax, [PARTITION_END] |
sub eax, [PARTITION_START] |
inc eax |
push eax |
push 0 |
push [PARTITION_START] |
push ebp |
push ebp |
mov ebp, esp |
mov esi, 'old' ; special value: there is no DISK structure |
push 1 ; bootsector read successfully |
call fat_create_partition |
add esp, 4*7 |
test eax, eax |
jz problem_fat_dec_count |
mov [fs_dependent_data_start.partition], eax |
mov al, [eax+FAT.fs_type] |
mov [fs_type], al |
popad |
call free_hd_channel |
mov [hd1_status], 0 ; free |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/iso9660.inc |
---|
0,0 → 1,761 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
uglobal |
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 |
IDE_Channel_1 db 0 |
IDE_Channel_2 db 0 |
endg |
reserve_cd: |
cli |
cmp [cd_status], 0 |
je reserve_ok2 |
sti |
call change_task |
jmp reserve_cd |
reserve_ok2: |
push eax |
mov eax, [CURRENT_TASK] |
shl eax, 5 |
mov eax, [eax+CURRENT_TASK+TASKDATA.pid] |
mov [cd_status], eax |
pop eax |
sti |
ret |
reserve_cd_channel: |
cmp [ChannelNumber], 1 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
cli |
cmp [IDE_Channel_1], 0 |
je .reserve_ok_1 |
sti |
call change_task |
jmp .IDE_Channel_1 |
.IDE_Channel_2: |
cli |
cmp [IDE_Channel_2], 0 |
je .reserve_ok_2 |
sti |
call change_task |
jmp .IDE_Channel_2 |
.reserve_ok_1: |
mov [IDE_Channel_1], 1 |
sti |
ret |
.reserve_ok_2: |
mov [IDE_Channel_2], 1 |
sti |
ret |
free_cd_channel: |
cmp [ChannelNumber], 1 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
mov [IDE_Channel_1], 0 |
sti |
ret |
.IDE_Channel_2: |
mov [IDE_Channel_2], 0 |
sti |
ret |
uglobal |
cd_status dd 0 |
endg |
;---------------------------------------------------------------- |
; |
; fs_CdRead - LFN variant for reading CD disk |
; |
; esi points to filename /dir1/dir2/.../dirn/file,0 |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_CdRead: |
push edi |
cmp byte [esi], 0 |
jnz @f |
.noaccess: |
pop edi |
.noaccess_2: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.noaccess_3: |
pop eax edx ecx edi |
jmp .noaccess_2 |
@@: |
call cd_find_lfn |
jnc .found |
pop edi |
cmp [DevErrorCode], 0 |
jne .noaccess_2 |
or ebx, -1 |
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 .noaccess |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6; end of file |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+10] ; ðåàëüíûé ðàçìåð ôàéëîâîé ñåêöèè |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 |
@@: |
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 |
.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 |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
.eof: |
mov ebx, edx |
pop eax edx ecx |
sub ebx, edx |
jmp .reteof |
;---------------------------------------------------------------- |
; |
; fs_CdReadFolder - LFN variant for reading CD disk folder |
; |
; esi points to filename /dir1/dir2/.../dirn/file,0 |
; ebx pointer to structure 32-bit number = first wanted block, 0+ |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = blocks read or 0xffffffff folder not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_CdReadFolder: |
push edi |
call cd_find_lfn |
jnc .found |
pop edi |
cmp [DevErrorCode], 0 |
jne .noaccess_1 |
or ebx, -1 |
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: |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
mov eax, [edi+2] ; eax=cluster |
mov [CDSectorAddress], eax |
mov eax, [edi+10] ; ðàçìåð äèðåêòðîðèè |
.doit: |
; init header |
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 |
; íà÷èíàåì ïåðåáðîñêó ÁÄÂÊ â ÓÑÂÊ |
;.mainloop: |
mov [cd_counter_block], dword 0 |
dec dword [CDSectorAddress] |
push ecx |
.read_to_buffer: |
inc dword [CDSectorAddress] |
mov [CDDataBuf_pointer], CDDataBuf |
call ReadCDWRetr ; ÷èòàåì ñåêòîð äèðåêòîðèè |
cmp [DevErrorCode], 0 |
jne .noaccess_1 |
call .get_names_from_buffer |
sub eax, 2048 |
; äèðåêòîðèÿ çàêîí÷èëàñü? |
ja .read_to_buffer |
mov edi, [cd_counter_block] |
mov [edx+8], edi |
mov edi, [ebx] |
sub [edx+4], edi |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
pop ecx edi |
mov ebx, [edx+4] |
ret |
.get_names_from_buffer: |
mov [cd_current_pointer_of_input_2], CDDataBuf |
push eax esi edi edx |
.get_names_from_buffer_1: |
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_1 |
test ecx, ecx |
jz .get_names_from_buffer_1 |
mov edi, [cd_counter_block] |
mov [edx+4], edi |
dec ecx |
mov esi, ebp |
mov edi, [cd_mem_location] |
add edi, 40 |
test dword [ebx+4], 1; 0=ANSI, 1=UNICODE |
jnz .unicode |
; jmp .unicode |
.ansi: |
cmp [cd_counter_block], 2 |
jbe .ansi_parent_directory |
cld |
lodsw |
xchg ah, al |
call uni2ansi_char |
cld |
stosb |
; ïðîâåðêà êîíöà ôàéëà |
mov ax, [esi] |
cmp ax, word 3B00h; ñåïàðàòîð êîíöà ôàéëà ';' |
je .cd_get_parameters_of_file_1 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax, byte [ebp-33] |
add eax, ebp |
sub eax, 34 |
cmp esi, eax |
je .cd_get_parameters_of_file_1 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax, byte [ebp-1] |
add eax, ebp |
cmp esi, eax |
jb .ansi |
.cd_get_parameters_of_file_1: |
mov [edi], byte 0 |
call cd_get_parameters_of_file |
add [cd_mem_location], 304 |
jmp .get_names_from_buffer_1 |
.ansi_parent_directory: |
cmp [cd_counter_block], 2 |
je @f |
mov [edi], byte '.' |
inc edi |
jmp .cd_get_parameters_of_file_1 |
@@: |
mov [edi], word '..' |
add edi, 2 |
jmp .cd_get_parameters_of_file_1 |
.unicode: |
cmp [cd_counter_block], 2 |
jbe .unicode_parent_directory |
cld |
movsw |
; ïðîâåðêà êîíöà ôàéëà |
mov ax, [esi] |
cmp ax, word 3B00h; ñåïàðàòîð êîíöà ôàéëà ';' |
je .cd_get_parameters_of_file_2 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax, byte [ebp-33] |
add eax, ebp |
sub eax, 34 |
cmp esi, eax |
je .cd_get_parameters_of_file_2 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax, byte [ebp-1] |
add eax, ebp |
cmp esi, eax |
jb .unicode |
.cd_get_parameters_of_file_2: |
mov [edi], word 0 |
call cd_get_parameters_of_file |
add [cd_mem_location], 560 |
jmp .get_names_from_buffer_1 |
.unicode_parent_directory: |
cmp [cd_counter_block], 2 |
je @f |
mov [edi], word 2E00h; '.' |
add edi, 2 |
jmp .cd_get_parameters_of_file_2 |
@@: |
mov [edi], dword 2E002E00h; '..' |
add edi, 4 |
jmp .cd_get_parameters_of_file_2 |
.end_buffer: |
pop edx edi esi eax |
ret |
cd_get_parameters_of_file: |
mov edi, [cd_mem_location] |
cd_get_parameters_of_file_1: |
; ïîëó÷àåì àòðèáóòû ôàéëà |
xor eax, eax |
; ôàéë íå àðõèâèðîâàëñÿ |
inc eax |
shl eax, 1 |
; ýòî êàòàëîã? |
test [ebp-8], byte 2 |
jz .file |
inc eax |
.file: |
; ìåòêà òîìà íå êàê â FAT, â ýòîì âèäå îòñóòñâóåò |
; ôàéë íå ÿâëÿåòñÿ ñèñòåìíûì |
shl eax, 3 |
; ôàéë ÿâëÿåòñÿ ñêðûòûì? (àòðèáóò ñóùåñòâîâàíèå) |
test [ebp-8], byte 1 |
jz .hidden |
inc eax |
.hidden: |
shl eax, 1 |
; ôàéë âñåãäà òîëüêî äëÿ ÷òåíèÿ, òàê êàê ýòî CD |
inc eax |
mov [edi], eax |
; ïîëó÷àåì âðåìÿ äëÿ ôàéëà |
;÷àñ |
movzx eax, byte [ebp-12] |
shl eax, 8 |
;ìèíóòà |
mov al, [ebp-11] |
shl eax, 8 |
;ñåêóíäà |
mov al, [ebp-10] |
;âðåìÿ ñîçäàíèÿ ôàéëà |
mov [edi+8], eax |
;âðåìÿ ïîñëåäíåãî äîñòóïà |
mov [edi+16], eax |
;âðåìÿ ïîñëåäíåé çàïèñè |
mov [edi+24], eax |
; ïîëó÷àåì äàòó äëÿ ôàéëà |
;ãîä |
movzx eax, byte [ebp-15] |
add eax, 1900 |
shl eax, 8 |
;ìåñÿö |
mov al, [ebp-14] |
shl eax, 8 |
;äåíü |
mov al, [ebp-13] |
;äàòà ñîçäàíèÿ ôàéëà |
mov [edi+12], eax |
;âðåìÿ ïîñëåäíåãî äîñòóïà |
mov [edi+20], eax |
;âðåìÿ ïîñëåäíåé çàïèñè |
mov [edi+28], eax |
; ïîëó÷àåì òèï äàííûõ èìåíè |
xor eax, eax |
test dword [ebx+4], 1; 0=ANSI, 1=UNICODE |
jnz .unicode_1 |
mov [edi+4], eax |
jmp @f |
.unicode_1: |
inc eax |
mov [edi+4], eax |
@@: |
; ïîëó÷àåì ðàçìåð ôàéëà â áàéòàõ |
xor eax, eax |
mov [edi+32+4], eax |
mov eax, [ebp-23] |
mov [edi+32], eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_CdGetFileInfo - LFN variant for CD |
; get file/directory attributes structure |
; |
;---------------------------------------------------------------- |
fs_CdGetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 |
ret |
@@: |
push edi |
call cd_find_lfn |
pushfd |
cmp [DevErrorCode], 0 |
jz @f |
popfd |
pop edi |
mov eax, 11 |
ret |
@@: |
popfd |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
mov edi, edx |
push ebp |
mov ebp, [cd_current_pointer_of_input] |
add ebp, 33 |
call cd_get_parameters_of_file_1 |
pop ebp |
and dword [edi+4], 0 |
pop edi |
xor eax, eax |
ret |
;---------------------------------------------------------------- |
cd_find_lfn: |
mov [cd_appl_data], 0 |
; in: esi+ebp -> name |
; out: CF=1 - file not found |
; else CF=0 and [cd_current_pointer_of_input] direntry |
push eax esi |
; 16 ñåêòîð íà÷àëî íàáîðà äåñêðèïòîðîâ òîìîâ |
call WaitUnitReady |
cmp [DevErrorCode], 0 |
jne .access_denied |
call prevent_medium_removal |
; òåñòîâîå ÷òåíèå |
mov [CDSectorAddress], dword 16 |
mov [CDDataBuf_pointer], CDDataBuf |
call ReadCDWRetr;_1 |
cmp [DevErrorCode], 0 |
jne .access_denied |
; âû÷èñëåíèå ïîñëåäíåé ñåññèè |
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: |
; ïðîâåðêà íà âøèâîñòü |
cmp [CDDataBuf+1], dword 'CD00' |
jne .access_denied |
cmp [CDDataBuf+5], byte '1' |
jne .access_denied |
; ñåêòîð ÿâëÿåòñÿ òåðìèíàòîðîì íàáîð äåñêðèïòîðîâ òîìîâ? |
cmp [CDDataBuf], byte 0xff |
je .access_denied |
; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì è óëó÷øåííûì äåñêðèïòîðîì òîìà? |
cmp [CDDataBuf], byte 0x2 |
jne .start |
; ñåêòîð ÿâëÿåòñÿ äîïîëíèòåëüíûì äåñêðèïòîðîì òîìà? |
cmp [CDDataBuf+6], byte 0x1 |
jne .start |
; ïàðàìåòðû root äèðåêòðîðèè |
mov eax, [CDDataBuf+0x9c+2]; íà÷àëî root äèðåêòðîðèè |
mov [CDSectorAddress], eax |
mov eax, [CDDataBuf+0x9c+10]; ðàçìåð root äèðåêòðîðèè |
cmp byte [esi], 0 |
jnz @f |
mov [cd_current_pointer_of_input], CDDataBuf+0x9c |
jmp .done |
@@: |
; íà÷èíàåì ïîèñê |
.mainloop: |
dec dword [CDSectorAddress] |
.read_to_buffer: |
inc dword [CDSectorAddress] |
mov [CDDataBuf_pointer], CDDataBuf |
call ReadCDWRetr ; ÷èòàåì ñåêòîð äèðåêòîðèè |
cmp [DevErrorCode], 0 |
jne .access_denied |
push ebp |
call cd_find_name_in_buffer |
pop ebp |
jnc .found |
sub eax, 2048 |
; äèðåêòîðèÿ çàêîí÷èëàñü? |
cmp eax, 0 |
ja .read_to_buffer |
; íåò èñêîìîãî ýëåìåíòà öåïî÷êè |
.access_denied: |
pop esi eax |
mov [cd_appl_data], 1 |
stc |
ret |
; èñêîìûé ýëåìåíò öåïî÷êè íàéäåí |
.found: |
; êîíåö ïóòè ôàéëà |
cmp byte [esi-1], 0 |
jz .done |
.nested: |
mov eax, [cd_current_pointer_of_input] |
push dword [eax+2] |
pop dword [CDSectorAddress] ; íà÷àëî äèðåêòîðèè |
mov eax, [eax+2+8]; ðàçìåð äèðåêòîðèè |
jmp .mainloop |
; óêàçàòåëü ôàéëà íàéäåí |
.done: |
test ebp, ebp |
jz @f |
mov esi, ebp |
xor ebp, ebp |
jmp .nested |
@@: |
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 ; âõîäû çàêîí÷èëèñü? |
jz .next_sector |
cmp ebp, CDDataBuf+2048 ; áóôåð çàêîí÷èëñÿ? |
jae .next_sector |
movzx eax, byte [ebp] |
add [cd_current_pointer_of_input_2], eax; ñëåäóþùèé âõîä êàòàëîãà |
add ebp, 33; óêàçàòåëü óñòàíîâëåí íà íà÷àëî èìåíè |
pop eax |
clc |
ret |
.next_sector: |
pop eax |
stc |
ret |
cd_compare_name: |
; compares ASCIIZ-names, case-insensitive (cp866 encoding) |
; in: esi->name, ebp->name |
; out: if names match: ZF=1 and esi->next component of name |
; else: ZF=0, esi is not changed |
; destroys eax |
push esi eax edi |
mov edi, ebp |
.loop: |
cld |
lodsb |
push eax |
call char_todown |
call ansi2uni_char |
xchg ah, al |
scasw |
pop eax |
je .coincides |
call char_toupper |
call ansi2uni_char |
xchg ah, al |
sub edi, 2 |
scasw |
jne .name_not_coincide |
.coincides: |
cmp [esi], byte '/'; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà |
je .done |
cmp [esi], byte 0; ðàçäåëèòåëü ïóòè, êîíåö èìåíè òåêóùåãî ýëåìåíòà |
je .done |
jmp .loop |
.name_not_coincide: |
pop edi eax esi |
stc |
ret |
.done: |
; ïðîâåðêà êîíöà ôàéëà |
cmp [edi], word 3B00h; ñåïàðàòîð êîíöà ôàéëà ';' |
je .done_1 |
; ïðîâåðêà äëÿ ôàéëîâ íå çàêàí÷èâàþùèõñÿ ñåïàðàòîðîì |
movzx eax, byte [ebp-33] |
add eax, ebp |
sub eax, 34 |
cmp edi, eax |
je .done_1 |
; ïðîâåðêà êîíöà ïàïêè |
movzx eax, byte [ebp-1] |
add eax, ebp |
cmp edi, eax |
jne .name_not_coincide |
.done_1: |
pop edi eax |
add esp, 4 |
inc esi |
clc |
ret |
char_todown: |
; convert character to uppercase, using cp866 encoding |
; in: al=symbol |
; out: al=converted symbol |
cmp al, 'A' |
jb .ret |
cmp al, 'Z' |
jbe .az |
cmp al, '' |
jb .ret |
cmp al, '' |
jb .rus1 |
cmp al, '' |
ja .ret |
; 0x90-0x9F -> 0xE0-0xEF |
add al, 'à'-'' |
.ret: |
ret |
.rus1: |
; 0x80-0x8F -> 0xA0-0xAF |
.az: |
add al, 0x20 |
ret |
uni2ansi_char: |
; convert UNICODE character in al to ANSI character in ax, using cp866 encoding |
; in: ax=UNICODE character |
; out: al=converted ANSI character |
cmp ax, 0x80 |
jb .ascii |
cmp ax, 0x401 |
jz .yo1 |
cmp ax, 0x451 |
jz .yo2 |
cmp ax, 0x410 |
jb .unk |
cmp ax, 0x440 |
jb .rus1 |
cmp ax, 0x450 |
jb .rus2 |
.unk: |
mov al, '_' |
jmp .doit |
.yo1: |
mov al, 'ð' |
jmp .doit |
.yo2: |
mov al, 'ñ' |
jmp .doit |
.rus1: |
; 0x410-0x43F -> 0x80-0xAF |
add al, 0x70 |
jmp .doit |
.rus2: |
; 0x440-0x44F -> 0xE0-0xEF |
add al, 0xA0 |
.ascii: |
.doit: |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/ntfs.inc |
---|
0,0 → 1,1829 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
ntfs_test_bootsec: |
; in: ebx->buffer, edx=size of partition |
; out: CF set <=> 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 negative and in [-31,-9] or positive and power of 2 |
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 |
ntfs_setup: ; CODE XREF: part_set.inc |
; By given bootsector, initialize some NTFS variables |
; call ntfs_test_bootsec ; checking boot sector was already |
; jc problem_fat_dec_count |
movzx eax, byte [ebx+13] |
mov [ntfs_data.sectors_per_cluster], eax |
mov eax, [ebx+0x28] |
add eax, [PARTITION_START] |
dec eax |
mov [PARTITION_END], eax |
mov [fs_type], 1 |
mov eax, [ebx+0x30] |
mov [ntfs_data.mft_cluster], eax |
mov eax, [ebx+0x38] |
mov [ntfs_data.mftmirr_cluster], eax |
movsx eax, byte [ebx+0x40] |
test eax, eax |
js .1 |
mul [ntfs_data.sectors_per_cluster] |
shl eax, 9 |
jmp .2 |
.1: |
neg eax |
mov ecx, eax |
mov eax, 1 |
shl eax, cl |
.2: |
mov [ntfs_data.frs_size], eax |
movsx eax, byte [ebx+0x44] |
test eax, eax |
js .3 |
mul [ntfs_data.sectors_per_cluster] |
shl eax, 9 |
jmp .4 |
.3: |
neg eax |
mov ecx, eax |
mov eax, 1 |
shl eax, cl |
.4: |
mov [ntfs_data.iab_size], eax |
; allocate space for buffers |
add eax, [ntfs_data.frs_size] |
push eax |
call kernel_alloc |
test eax, eax |
jz problem_fat_dec_count |
mov [ntfs_data.frs_buffer], eax |
add eax, [ntfs_data.frs_size] |
mov [ntfs_data.iab_buffer], eax |
; read $MFT disposition |
mov eax, [ntfs_data.mft_cluster] |
mul [ntfs_data.sectors_per_cluster] |
call ntfs_read_frs_sector |
cmp [hd_error], 0 |
jnz .usemirr |
cmp dword [ebx], 'FILE' |
jnz .usemirr |
call ntfs_restore_usa_frs |
jnc .mftok |
.usemirr: |
and [hd_error], 0 |
mov eax, [ntfs_data.mftmirr_cluster] |
mul [ntfs_data.sectors_per_cluster] |
call ntfs_read_frs_sector |
cmp [hd_error], 0 |
jnz @f |
cmp dword [ebx], 'FILE' |
jnz @f |
call ntfs_restore_usa_frs |
jnc .mftok |
@@: |
; $MFT and $MFTMirr invalid! |
.fail_free_frs: |
push [ntfs_data.frs_buffer] |
call kernel_free |
jmp problem_fat_dec_count |
.fail_free_mft: |
push [ntfs_data.mft_retrieval] |
call kernel_free |
jmp .fail_free_frs |
.mftok: |
; read $MFT table retrieval information |
; start with one page, increase if not enough (when MFT too fragmented) |
push ebx |
push 0x1000 |
call kernel_alloc |
pop ebx |
test eax, eax |
jz .fail_free_frs |
mov [ntfs_data.mft_retrieval], eax |
and [ntfs_data.mft_retrieval_size], 0 |
mov [ntfs_data.mft_retrieval_alloc], 0x1000/8 |
; $MFT base record must contain unnamed non-resident $DATA attribute |
movzx eax, word [ebx+14h] |
add eax, ebx |
.scandata: |
cmp dword [eax], -1 |
jz .fail_free_mft |
cmp dword [eax], 0x80 |
jnz @f |
cmp byte [eax+9], 0 |
jz .founddata |
@@: |
add eax, [eax+4] |
jmp .scandata |
.founddata: |
cmp byte [eax+8], 0 |
jz .fail_free_mft |
; load first portion of $DATA attribute retrieval information |
mov edx, [eax+0x18] |
mov [ntfs_data.mft_retrieval_end], edx |
mov esi, eax |
movzx eax, word [eax+0x20] |
add esi, eax |
sub esp, 10h |
.scanmcb: |
call ntfs_decode_mcb_entry |
jnc .scanmcbend |
call .get_mft_retrieval_ptr |
mov edx, [esp] ; block length |
mov [eax], edx |
mov edx, [esp+8] ; block addr (relative) |
mov [eax+4], edx |
inc [ntfs_data.mft_retrieval_size] |
jmp .scanmcb |
.scanmcbend: |
add esp, 10h |
; there may be other portions of $DATA attribute in auxiliary records; |
; if they will be needed, they will be loaded later |
mov [ntfs_data.cur_index_size], 0x1000/0x200 |
push 0x1000 |
call kernel_alloc |
test eax, eax |
jz .fail_free_mft |
mov [ntfs_data.cur_index_buf], eax |
popad |
call free_hd_channel |
and [hd1_status], 0 |
ret |
.get_mft_retrieval_ptr: |
pushad |
mov eax, [ntfs_data.mft_retrieval_size] |
cmp eax, [ntfs_data.mft_retrieval_alloc] |
jnz .ok |
add eax, 0x1000/8 |
mov [ntfs_data.mft_retrieval_alloc], eax |
shl eax, 3 |
push eax |
call kernel_alloc |
test eax, eax |
jnz @f |
popad |
add esp, 14h |
jmp .fail_free_mft |
@@: |
mov esi, [ntfs_data.mft_retrieval] |
mov edi, eax |
mov ecx, [ntfs_data.mft_retrieval_size] |
add ecx, ecx |
rep movsd |
push [ntfs_data.mft_retrieval] |
mov [ntfs_data.mft_retrieval], eax |
call kernel_free |
mov eax, [ntfs_data.mft_retrieval_size] |
.ok: |
shl eax, 3 |
add eax, [ntfs_data.mft_retrieval] |
mov [esp+28], eax |
popad |
ret |
ntfs_read_frs_sector: |
push eax ecx |
add eax, [PARTITION_START] |
mov ecx, [ntfs_data.frs_size] |
shr ecx, 9 |
mov ebx, [ntfs_data.frs_buffer] |
push ebx |
@@: |
call hd_read |
cmp [hd_error], 0 |
jnz .fail |
add ebx, 0x200 |
inc eax |
loop @b |
.fail: |
pop ebx |
pop ecx eax |
ret |
uglobal |
align 4 |
ntfs_cur_attr dd ? |
ntfs_cur_iRecord dd ? |
ntfs_cur_offs dd ? ; in sectors |
ntfs_cur_size dd ? ; in sectors |
ntfs_cur_buf dd ? |
ntfs_cur_read dd ? ; [output] |
ntfs_bCanContinue db ? |
rb 3 |
ntfs_attrlist_buf rb 0x400 |
ntfs_attrlist_mft_buf rb 0x400 |
ntfs_bitmap_buf rb 0x400 |
ntfs_attr_iRecord dd ? |
ntfs_attr_iBaseRecord dd ? |
ntfs_attr_offs dd ? |
ntfs_attr_list dd ? |
ntfs_attr_size dq ? |
ntfs_cur_tail dd ? |
endg |
ntfs_read_attr: |
; in: global variables |
; out: [ntfs_cur_read] |
pushad |
and [ntfs_cur_read], 0 |
cmp [ntfs_cur_iRecord], 0 |
jnz .nomft |
cmp [ntfs_cur_attr], 0x80 |
jnz .nomft |
mov eax, [ntfs_data.mft_retrieval_end] |
inc eax |
mul [ntfs_data.sectors_per_cluster] |
cmp eax, [ntfs_cur_offs] |
jbe .nomft |
; precalculated part of $Mft $DATA |
mov esi, [ntfs_data.mft_retrieval] |
mov eax, [ntfs_cur_offs] |
xor edx, edx |
div [ntfs_data.sectors_per_cluster] |
; eax = VCN, edx = offset in sectors from beginning of cluster |
xor ecx, ecx ; ecx will contain LCN |
.mftscan: |
add ecx, [esi+4] |
sub eax, [esi] |
jb @f |
add esi, 8 |
push eax |
mov eax, [ntfs_data.mft_retrieval_end] |
shl eax, 3 |
add eax, [ntfs_data.mft_retrieval] |
cmp eax, esi |
pop eax |
jnz .mftscan |
jmp .nomft |
@@: |
push ecx |
add ecx, eax |
add ecx, [esi] |
push eax |
push edx |
mov eax, [ntfs_data.sectors_per_cluster] |
mul ecx |
; eax = sector on partition |
add eax, [PARTITION_START] |
pop edx |
add eax, edx |
mov ebx, [ntfs_cur_buf] |
pop ecx |
neg ecx |
imul ecx, [ntfs_data.sectors_per_cluster] |
sub ecx, edx |
cmp ecx, [ntfs_cur_size] |
jb @f |
mov ecx, [ntfs_cur_size] |
@@: |
; ecx = number of sequential sectors to read |
call hd_read |
cmp [hd_error], 0 |
jnz .errread |
add [ntfs_cur_read], 0x200 |
dec [ntfs_cur_size] |
inc [ntfs_cur_offs] |
add ebx, 0x200 |
mov [ntfs_cur_buf], ebx |
inc eax |
loop @b |
pop ecx |
xor eax, eax |
xor edx, edx |
cmp [ntfs_cur_size], eax |
jz @f |
add esi, 8 |
push eax |
mov eax, [ntfs_data.mft_retrieval_end] |
shl eax, 3 |
add eax, [ntfs_data.mft_retrieval] |
cmp eax, esi |
pop eax |
jz .nomft |
jmp .mftscan |
@@: |
popad |
ret |
.errread: |
pop ecx |
.errret: |
stc |
popad |
ret |
.nomft: |
; 1. Read file record. |
; N.B. This will do recursive call of read_attr for $MFT::$Data. |
mov eax, [ntfs_cur_iRecord] |
mov [ntfs_attr_iRecord], eax |
and [ntfs_attr_list], 0 |
or dword [ntfs_attr_size], -1 |
or dword [ntfs_attr_size+4], -1 |
or [ntfs_attr_iBaseRecord], -1 |
call ntfs_read_file_record |
test eax, eax |
jz .errret |
; 2. Find required attribute. |
mov eax, [ntfs_data.frs_buffer] |
; a) For auxiliary records, read base record |
; N.B. If base record is present, |
; base iRecord may be 0 (for $Mft), but SequenceNumber is nonzero |
cmp dword [eax+24h], 0 |
jz @f |
mov eax, [eax+20h] |
; test eax, eax |
; jz @f |
.beginfindattr: |
mov [ntfs_attr_iRecord], eax |
call ntfs_read_file_record |
test eax, eax |
jz .errret |
@@: |
; b) Scan for required attribute and for $ATTR_LIST |
mov eax, [ntfs_data.frs_buffer] |
movzx ecx, word [eax+14h] |
add eax, ecx |
mov ecx, [ntfs_cur_attr] |
and [ntfs_attr_offs], 0 |
.scanattr: |
cmp dword [eax], -1 |
jz .scandone |
cmp dword [eax], ecx |
jz .okattr |
cmp [ntfs_attr_iBaseRecord], -1 |
jnz .scancont |
cmp dword [eax], 0x20 ; $ATTR_LIST |
jnz .scancont |
mov [ntfs_attr_list], eax |
jmp .scancont |
.okattr: |
; ignore named $DATA attributes (aka NTFS streams) |
cmp ecx, 0x80 |
jnz @f |
cmp byte [eax+9], 0 |
jnz .scancont |
@@: |
mov [ntfs_attr_offs], eax |
.scancont: |
add eax, [eax+4] |
jmp .scanattr |
.continue: |
pushad |
and [ntfs_cur_read], 0 |
.scandone: |
; c) Check for required offset and length |
mov ecx, [ntfs_attr_offs] |
jecxz .noattr |
push [ntfs_cur_size] |
push [ntfs_cur_read] |
call .doreadattr |
pop edx |
pop eax |
jc @f |
cmp [ntfs_bCanContinue], 0 |
jz @f |
sub edx, [ntfs_cur_read] |
neg edx |
shr edx, 9 |
sub eax, edx |
mov [ntfs_cur_size], eax |
jnz .not_in_cur |
@@: |
popad |
ret |
.noattr: |
.not_in_cur: |
cmp [ntfs_cur_attr], 0x20 |
jz @f |
mov ecx, [ntfs_attr_list] |
test ecx, ecx |
jnz .lookattr |
.ret_is_attr: |
cmp [ntfs_attr_offs], 1 ; CF set <=> ntfs_attr_offs == 0 |
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, [ntfs_attr_iBaseRecord] |
cmp eax, -1 |
jz @f |
call ntfs_read_file_record |
test eax, eax |
jz .errret |
or [ntfs_attr_iBaseRecord], -1 |
@@: |
push [ntfs_cur_offs] |
push [ntfs_cur_size] |
push [ntfs_cur_read] |
push [ntfs_cur_buf] |
push dword [ntfs_attr_size] |
push dword [ntfs_attr_size+4] |
or dword [ntfs_attr_size], -1 |
or dword [ntfs_attr_size+4], -1 |
and [ntfs_cur_offs], 0 |
mov [ntfs_cur_size], 2 |
and [ntfs_cur_read], 0 |
mov eax, ntfs_attrlist_buf |
cmp [ntfs_cur_iRecord], 0 |
jnz @f |
mov eax, ntfs_attrlist_mft_buf |
@@: |
mov [ntfs_cur_buf], eax |
push eax |
call .doreadattr |
pop esi |
mov edx, 1 |
pop dword [ntfs_attr_size+4] |
pop dword [ntfs_attr_size] |
mov ebp, [ntfs_cur_read] |
pop [ntfs_cur_buf] |
pop [ntfs_cur_read] |
pop [ntfs_cur_size] |
pop [ntfs_cur_offs] |
jc .errret |
or edi, -1 |
lea ebp, [ebp+esi-1Ah] |
.scanliststart: |
mov eax, [ntfs_cur_attr] |
.scanlist: |
cmp esi, ebp |
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 |
mov eax, dword [ntfs_attr_size] |
and eax, dword [ntfs_attr_size+4] |
cmp eax, -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 |
test eax, eax |
jnz @f |
.errret_pop: |
pop eax |
jmp .errret |
@@: |
mov eax, [ntfs_data.frs_buffer] |
movzx ecx, word [eax+14h] |
add eax, ecx |
mov ecx, [ntfs_cur_attr] |
@@: |
cmp dword [eax], -1 |
jz .errret_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 [ntfs_attr_size], eax |
and dword [ntfs_attr_size+4], 0 |
jmp .testfz |
.sdnores: |
mov ecx, [eax+30h] |
mov dword [ntfs_attr_size], ecx |
mov ecx, [eax+34h] |
mov dword [ntfs_attr_size+4], ecx |
.testfz: |
xor eax, eax |
.testf: |
imul eax, [ntfs_data.sectors_per_cluster] |
cmp eax, [ntfs_cur_offs] |
pop eax |
ja @f |
mov edi, [esi+10h] ; keep previous iRecord |
jmp .scanlistcont |
@@: |
.scanlistfound: |
cmp edi, -1 |
jnz @f |
popad |
ret |
@@: |
mov eax, [ntfs_cur_iRecord] |
mov [ntfs_attr_iBaseRecord], eax |
mov eax, edi |
jmp .beginfindattr |
.sde: |
popad |
stc |
ret |
.scanlistdone: |
sub ebp, ntfs_attrlist_buf-1Ah |
cmp [ntfs_cur_iRecord], 0 |
jnz @f |
sub ebp, ntfs_attrlist_mft_buf-ntfs_attrlist_buf |
@@: |
cmp ebp, 0x400 |
jnz .scanlistfound |
inc edx |
push esi edi |
mov esi, ntfs_attrlist_buf+0x200 |
mov edi, ntfs_attrlist_buf |
cmp [ntfs_cur_iRecord], 0 |
jnz @f |
mov esi, ntfs_attrlist_mft_buf+0x200 |
mov edi, ntfs_attrlist_mft_buf |
@@: |
mov ecx, 0x200/4 |
rep movsd |
mov eax, edi |
pop edi esi |
sub esi, 0x200 |
push [ntfs_cur_offs] |
push [ntfs_cur_size] |
push [ntfs_cur_read] |
push [ntfs_cur_buf] |
push dword [ntfs_attr_size] |
push dword [ntfs_attr_size+4] |
or dword [ntfs_attr_size], -1 |
or dword [ntfs_attr_size+4], -1 |
mov [ntfs_cur_offs], edx |
mov [ntfs_cur_size], 1 |
and [ntfs_cur_read], 0 |
mov [ntfs_cur_buf], eax |
mov ecx, [ntfs_attr_list] |
push esi edx |
call .doreadattr |
pop edx esi |
mov ebp, [ntfs_cur_read] |
pop dword [ntfs_attr_size+4] |
pop dword [ntfs_attr_size] |
pop [ntfs_cur_buf] |
pop [ntfs_cur_read] |
pop [ntfs_cur_size] |
pop [ntfs_cur_offs] |
jc .errret |
add ebp, ntfs_attrlist_buf+0x200-0x1A |
cmp [ntfs_cur_iRecord], 0 |
jnz .scanliststart |
add ebp, ntfs_attrlist_mft_buf-ntfs_attrlist_buf |
jmp .scanliststart |
.doreadattr: |
mov [ntfs_bCanContinue], 0 |
cmp byte [ecx+8], 0 |
jnz .nonresident |
mov eax, [ecx+10h] ; length |
mov esi, eax |
mov edx, [ntfs_cur_offs] |
shr eax, 9 |
cmp eax, edx |
jb .okret |
shl edx, 9 |
sub esi, edx |
movzx eax, word [ecx+14h] |
add edx, eax |
add edx, ecx ; edx -> data |
mov eax, [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 [ntfs_cur_read], eax |
mov ecx, eax |
mov eax, edx |
mov ebx, [ntfs_cur_buf] |
call memmove |
and [ntfs_cur_size], 0 ; CF=0 |
ret |
.nonresident: |
; Not all auxiliary records contain correct FileSize info |
mov eax, dword [ntfs_attr_size] |
mov edx, dword [ntfs_attr_size+4] |
push eax |
and eax, edx |
cmp eax, -1 |
pop eax |
jnz @f |
mov eax, [ecx+30h] ; FileSize |
mov edx, [ecx+34h] |
mov dword [ntfs_attr_size], eax |
mov dword [ntfs_attr_size+4], edx |
@@: |
add eax, 0x1FF |
adc edx, 0 |
shrd eax, edx, 9 |
sub eax, [ntfs_cur_offs] |
ja @f |
; return with nothing read |
and [ntfs_cur_size], 0 |
.okret: |
clc |
ret |
@@: |
; reduce read length |
and [ntfs_cur_tail], 0 |
cmp [ntfs_cur_size], eax |
jb @f |
mov [ntfs_cur_size], eax |
mov eax, dword [ntfs_attr_size] |
and eax, 0x1FF |
mov [ntfs_cur_tail], eax |
@@: |
cmp [ntfs_cur_size], 0 |
jz .okret |
mov eax, [ntfs_cur_offs] |
xor edx, edx |
div [ntfs_data.sectors_per_cluster] |
sub eax, [ecx+10h] ; first_vbo |
jb .okret |
; eax = cluster, edx = starting sector |
sub esp, 10h |
movzx esi, word [ecx+20h] ; mcb_info_ofs |
add esi, ecx |
xor ebp, ebp |
.readloop: |
call ntfs_decode_mcb_entry |
jnc .break |
add ebp, [esp+8] |
sub eax, [esp] |
jae .readloop |
push ecx |
push eax |
add eax, [esp+8] |
add eax, ebp |
imul eax, [ntfs_data.sectors_per_cluster] |
add eax, edx |
add eax, [PARTITION_START] |
pop ecx |
neg ecx |
imul ecx, [ntfs_data.sectors_per_cluster] |
sub ecx, edx |
cmp ecx, [ntfs_cur_size] |
jb @f |
mov ecx, [ntfs_cur_size] |
@@: |
mov ebx, [ntfs_cur_buf] |
@@: |
call hd_read |
cmp [hd_error], 0 |
jnz .errread2 |
add ebx, 0x200 |
mov [ntfs_cur_buf], ebx |
inc eax |
add [ntfs_cur_read], 0x200 |
dec [ntfs_cur_size] |
inc [ntfs_cur_offs] |
loop @b |
pop ecx |
xor eax, eax |
xor edx, edx |
cmp [ntfs_cur_size], 0 |
jnz .readloop |
add esp, 10h |
mov eax, [ntfs_cur_tail] |
test eax, eax |
jz @f |
sub eax, 0x200 |
add [ntfs_cur_read], eax |
@@: |
clc |
ret |
.errread2: |
pop ecx |
add esp, 10h |
stc |
ret |
.break: |
add esp, 10h ; CF=0 |
mov [ntfs_bCanContinue], 1 |
ret |
ntfs_read_file_record: |
; in: eax=iRecord |
; out: [ntfs_data.frs_buffer] contains information |
; eax=0 - failed, eax=1 - success |
; Read attr $DATA of $Mft, starting from eax*[ntfs_data.frs_size] |
push ecx edx |
mov ecx, [ntfs_data.frs_size] |
mul ecx |
shrd eax, edx, 9 |
shr edx, 9 |
jnz .err |
push [ntfs_attr_iRecord] |
push [ntfs_attr_iBaseRecord] |
push [ntfs_attr_offs] |
push [ntfs_attr_list] |
push dword [ntfs_attr_size+4] |
push dword [ntfs_attr_size] |
push [ntfs_cur_iRecord] |
push [ntfs_cur_attr] |
push [ntfs_cur_offs] |
push [ntfs_cur_size] |
push [ntfs_cur_buf] |
push [ntfs_cur_read] |
mov [ntfs_cur_attr], 0x80 ; $DATA |
and [ntfs_cur_iRecord], 0 ; $Mft |
mov [ntfs_cur_offs], eax |
shr ecx, 9 |
mov [ntfs_cur_size], ecx |
mov eax, [ntfs_data.frs_buffer] |
mov [ntfs_cur_buf], eax |
call ntfs_read_attr |
mov eax, [ntfs_cur_read] |
pop [ntfs_cur_read] |
pop [ntfs_cur_buf] |
pop [ntfs_cur_size] |
pop [ntfs_cur_offs] |
pop [ntfs_cur_attr] |
pop [ntfs_cur_iRecord] |
pop dword [ntfs_attr_size] |
pop dword [ntfs_attr_size+4] |
pop [ntfs_attr_list] |
pop [ntfs_attr_offs] |
pop [ntfs_attr_iBaseRecord] |
pop [ntfs_attr_iRecord] |
pop edx ecx |
jc .errret |
cmp eax, [ntfs_data.frs_size] |
jnz .errret |
mov eax, [ntfs_data.frs_buffer] |
cmp dword [eax], 'FILE' |
jnz .errret |
push ebx |
mov ebx, eax |
call ntfs_restore_usa_frs |
pop ebx |
setnc al |
movzx eax, al |
.ret: |
ret |
.err: |
pop edx ecx |
.errret: |
xor eax, eax |
ret |
ntfs_restore_usa_frs: |
mov eax, [ntfs_data.frs_size] |
ntfs_restore_usa: |
pushad |
shr eax, 9 |
mov ecx, eax |
inc eax |
cmp [ebx+6], ax |
jnz .err |
movzx eax, word [ebx+4] |
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: |
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 |
unichar_toupper: |
push eax |
call uni2ansi_char |
cmp al, '_' |
jz .unk |
add esp, 4 |
call char_toupper |
jmp ansi2uni_char |
.unk: |
pop eax |
ret |
ntfs_find_lfn: |
; in: esi+ebp -> name |
; out: CF=1 - file not found |
; else CF=0, [ntfs_cur_iRecord] valid, eax->record in parent directory |
mov [ntfs_cur_iRecord], 5 ; start parse from root cluster |
.doit2: |
mov [ntfs_cur_attr], 0x90 ; $INDEX_ROOT |
and [ntfs_cur_offs], 0 |
mov eax, [ntfs_data.cur_index_size] |
mov [ntfs_cur_size], eax |
mov eax, [ntfs_data.cur_index_buf] |
mov [ntfs_cur_buf], eax |
call ntfs_read_attr |
jnc @f |
.ret: |
ret |
@@: |
cmp [ntfs_cur_read], 0x20 |
jc .ret |
pushad |
mov esi, [ntfs_data.cur_index_buf] |
mov eax, [esi+14h] |
add eax, 10h |
cmp [ntfs_cur_read], eax |
jae .readok1 |
add eax, 1FFh |
shr eax, 9 |
cmp eax, [ntfs_data.cur_index_size] |
ja @f |
.stc_ret: |
popad |
stc |
ret |
@@: |
; reallocate |
push eax |
push [ntfs_data.cur_index_buf] |
call kernel_free |
pop eax |
mov [ntfs_data.cur_index_size], eax |
push eax |
call kernel_alloc |
test eax, eax |
jnz @f |
and [ntfs_data.cur_index_size], 0 |
and [ntfs_data.cur_index_buf], 0 |
jmp .stc_ret |
@@: |
mov [ntfs_data.cur_index_buf], eax |
popad |
jmp .doit2 |
.readok1: |
mov ebp, [esi+8] ; subnode_size |
shr ebp, 9 |
cmp ebp, [ntfs_data.cur_index_size] |
jbe .ok2 |
push esi ebp |
push ebp |
call kernel_alloc |
pop ebp esi |
test eax, eax |
jz .stc_ret |
mov edi, eax |
mov ecx, [ntfs_data.cur_index_size] |
shl ecx, 9-2 |
rep movsd |
mov esi, eax |
mov [ntfs_data.cur_index_size], ebp |
push esi ebp |
push [ntfs_data.cur_index_buf] |
call kernel_free |
pop ebp esi |
mov [ntfs_data.cur_index_buf], esi |
.ok2: |
add esi, 10h |
mov edi, [esp+4] |
; edi -> name, esi -> current index data, ebp = subnode size |
.scanloop: |
add esi, [esi] |
.scanloopint: |
test byte [esi+0Ch], 2 |
jnz .subnode |
push esi |
add esi, 0x52 |
movzx ecx, byte [esi-2] |
push edi |
@@: |
lodsw |
call unichar_toupper |
push eax |
mov al, [edi] |
inc edi |
cmp al, '/' |
jz .slash |
call char_toupper |
call ansi2uni_char |
cmp ax, [esp] |
pop eax |
loopz @b |
jz .found |
pop edi |
pop esi |
jb .subnode |
.scanloopcont: |
movzx eax, word [esi+8] |
add esi, eax |
jmp .scanloopint |
.slash: |
pop eax |
pop edi |
pop esi |
.subnode: |
test byte [esi+0Ch], 1 |
jz .notfound |
movzx eax, word [esi+8] |
mov eax, [esi+eax-8] |
mul [ntfs_data.sectors_per_cluster] |
mov [ntfs_cur_offs], eax |
mov [ntfs_cur_attr], 0xA0 ; $INDEX_ALLOCATION |
mov [ntfs_cur_size], ebp |
mov eax, [ntfs_data.cur_index_buf] |
mov esi, eax |
mov [ntfs_cur_buf], eax |
call ntfs_read_attr |
mov eax, ebp |
shl eax, 9 |
cmp [ntfs_cur_read], eax |
jnz .notfound |
cmp dword [esi], 'INDX' |
jnz .notfound |
mov ebx, esi |
call ntfs_restore_usa |
jc .notfound |
add esi, 0x18 |
jmp .scanloop |
.notfound: |
popad |
stc |
ret |
.found: |
cmp byte [edi], 0 |
jz .done |
cmp byte [edi], '/' |
jz .next |
pop edi |
pop esi |
jmp .scanloopcont |
.done: |
.next: |
pop esi |
pop esi |
mov eax, [esi] |
mov [ntfs_cur_iRecord], eax |
mov [esp+1Ch], esi |
mov [esp+4], edi |
popad |
inc esi |
cmp byte [esi-1], 0 |
jnz .doit2 |
test ebp, ebp |
jz @f |
mov esi, ebp |
xor ebp, ebp |
jmp .doit2 |
@@: |
ret |
;---------------------------------------------------------------- |
; |
; ntfs_HdRead - read NTFS hard disk |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdRead: |
cmp byte [esi], 0 |
jnz @f |
or ebx, -1 |
push ERROR_ACCESS_DENIED |
pop eax |
ret |
@@: |
call ntfs_find_lfn |
jnc .found |
or ebx, -1 |
push ERROR_FILE_NOT_FOUND |
pop eax |
ret |
.found: |
mov [ntfs_cur_attr], 0x80 ; $DATA |
and [ntfs_cur_offs], 0 |
and [ntfs_cur_size], 0 |
call ntfs_read_attr |
jnc @f |
or ebx, -1 |
push ERROR_ACCESS_DENIED |
pop eax |
ret |
@@: |
pushad |
and dword [esp+10h], 0 |
xor eax, eax |
test ebx, ebx |
jz .zero1 |
cmp dword [ebx+4], 0x200 |
jb @f |
.eof0: |
popad |
xor ebx, ebx |
.eof: |
push ERROR_END_OF_FILE |
pop eax |
ret |
@@: |
mov eax, [ebx] |
test eax, 0x1FF |
jz .alignedstart |
push edx |
mov edx, [ebx+4] |
shrd eax, edx, 9 |
pop edx |
mov [ntfs_cur_offs], eax |
mov [ntfs_cur_size], 1 |
mov [ntfs_cur_buf], ntfs_bitmap_buf |
call ntfs_read_attr.continue |
mov eax, [ebx] |
and eax, 0x1FF |
lea esi, [ntfs_bitmap_buf+eax] |
sub eax, [ntfs_cur_read] |
jae .eof0 |
neg eax |
push ecx |
cmp ecx, eax |
jb @f |
mov ecx, eax |
@@: |
mov [esp+10h+4], ecx |
mov edi, edx |
rep movsb |
mov edx, edi |
pop ecx |
sub ecx, [esp+10h] |
jnz @f |
.retok: |
popad |
xor eax, eax |
ret |
@@: |
cmp [ntfs_cur_read], 0x200 |
jz .alignedstart |
.eof_ebx: |
popad |
jmp .eof |
.alignedstart: |
mov eax, [ebx] |
push edx |
mov edx, [ebx+4] |
add eax, 511 |
adc edx, 0 |
shrd eax, edx, 9 |
pop edx |
.zero1: |
mov [ntfs_cur_offs], eax |
mov [ntfs_cur_buf], edx |
mov eax, ecx |
shr eax, 9 |
mov [ntfs_cur_size], eax |
add eax, [ntfs_cur_offs] |
push eax |
call ntfs_read_attr.continue |
pop [ntfs_cur_offs] |
mov eax, [ntfs_cur_read] |
add [esp+10h], eax |
mov eax, ecx |
and eax, not 0x1FF |
cmp [ntfs_cur_read], eax |
jnz .eof_ebx |
and ecx, 0x1FF |
jz .retok |
add edx, [ntfs_cur_read] |
mov [ntfs_cur_size], 1 |
mov [ntfs_cur_buf], ntfs_bitmap_buf |
call ntfs_read_attr.continue |
cmp [ntfs_cur_read], ecx |
jb @f |
mov [ntfs_cur_read], ecx |
@@: |
xchg ecx, [ntfs_cur_read] |
push ecx |
mov edi, edx |
mov esi, ntfs_bitmap_buf |
add [esp+10h+4], ecx |
rep movsb |
pop ecx |
xor eax, eax |
cmp ecx, [ntfs_cur_read] |
jz @f |
mov al, ERROR_END_OF_FILE |
@@: |
mov [esp+1Ch], eax |
popad |
ret |
;---------------------------------------------------------------- |
; |
; ntfs_HdReadFolder - read NTFS hard disk folder |
; |
; esi points to filename |
; ebx pointer to structure 32-bit number = first wanted block, 0+ |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = blocks read or 0xffffffff folder not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdReadFolder: |
mov eax, 5 ; root cluster |
cmp byte [esi], 0 |
jz .doit |
call ntfs_find_lfn |
jnc .doit2 |
.notfound: |
or ebx, -1 |
push ERROR_FILE_NOT_FOUND |
.pop_ret: |
pop eax |
ret |
.doit: |
mov [ntfs_cur_iRecord], eax |
.doit2: |
mov [ntfs_cur_attr], 0x10 ; $STANDARD_INFORMATION |
and [ntfs_cur_offs], 0 |
mov [ntfs_cur_size], 1 |
mov [ntfs_cur_buf], ntfs_bitmap_buf |
call ntfs_read_attr |
jc .notfound |
mov [ntfs_cur_attr], 0x90 ; $INDEX_ROOT |
and [ntfs_cur_offs], 0 |
mov eax, [ntfs_data.cur_index_size] |
mov [ntfs_cur_size], eax |
mov eax, [ntfs_data.cur_index_buf] |
mov [ntfs_cur_buf], eax |
call ntfs_read_attr |
jnc .ok |
cmp [hd_error], 0 |
jz .notfound |
or ebx, -1 |
push 11 |
jmp .pop_ret |
.ok: |
cmp [ntfs_cur_read], 0x20 |
jae @f |
or ebx, -1 |
.fserr: |
push ERROR_FAT_TABLE |
jmp .pop_ret |
@@: |
pushad |
mov esi, [ntfs_data.cur_index_buf] |
mov eax, [esi+14h] |
add eax, 10h |
cmp [ntfs_cur_read], eax |
jae .readok1 |
add eax, 1FFh |
shr eax, 9 |
cmp eax, [ntfs_data.cur_index_size] |
ja @f |
popad |
jmp .fserr |
@@: |
; reallocate |
push eax |
push [ntfs_data.cur_index_buf] |
call kernel_free |
pop eax |
mov [ntfs_data.cur_index_size], eax |
push eax |
call kernel_alloc |
test eax, eax |
jnz @f |
and [ntfs_data.cur_index_size], 0 |
and [ntfs_data.cur_index_buf], 0 |
.nomem: |
popad |
or ebx, -1 |
push 12 |
pop eax |
ret |
@@: |
mov [ntfs_data.cur_index_buf], eax |
popad |
jmp .doit2 |
.readok1: |
mov ebp, [esi+8] ; subnode_size |
shr ebp, 9 |
cmp ebp, [ntfs_data.cur_index_size] |
jbe .ok2 |
push esi ebp |
push ebp |
call kernel_alloc |
pop ebp esi |
test eax, eax |
jz .nomem |
mov edi, eax |
mov ecx, [ntfs_data.cur_index_size] |
shl ecx, 9-2 |
rep movsd |
mov esi, eax |
mov [ntfs_data.cur_index_size], ebp |
push esi ebp |
push [ntfs_data.cur_index_buf] |
call kernel_free |
pop ebp esi |
mov [ntfs_data.cur_index_buf], esi |
.ok2: |
add esi, 10h |
mov ebx, [esp+10h] |
mov edx, [esp+14h] |
push dword [ebx+4] ; read ANSI/UNICODE name |
mov ebx, [ebx] |
; init header |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
mov byte [edx], 1 ; version |
mov ecx, [esp+4+18h] |
push edx |
mov edx, esp |
; edi -> BDFE, esi -> current index data, ebp = subnode size, ebx = first wanted block, |
; ecx = number of blocks to read |
; edx -> parameters block: dd <output>, dd <flags> |
cmp [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] |
.dump_root: |
test byte [esi+0Ch], 2 |
jnz .dump_root_done |
call .add_entry |
movzx eax, word [esi+8] |
add esi, eax |
jmp .dump_root |
.dump_root_done: |
; now dump all subnodes |
push ecx edi |
mov edi, ntfs_bitmap_buf |
mov [ntfs_cur_buf], edi |
mov ecx, 0x400/4 |
xor eax, eax |
rep stosd |
mov [ntfs_cur_attr], 0xB0 ; $BITMAP |
and [ntfs_cur_offs], 0 |
mov [ntfs_cur_size], 2 |
call ntfs_read_attr |
pop edi ecx |
push 0 ; save offset in $BITMAP attribute |
and [ntfs_cur_offs], 0 |
.dumploop: |
mov [ntfs_cur_attr], 0xA0 |
mov [ntfs_cur_size], ebp |
mov eax, [ntfs_data.cur_index_buf] |
mov esi, eax |
mov [ntfs_cur_buf], eax |
push [ntfs_cur_offs] |
mov eax, [ntfs_cur_offs] |
imul eax, ebp |
mov [ntfs_cur_offs], eax |
call ntfs_read_attr |
pop [ntfs_cur_offs] |
mov eax, ebp |
shl eax, 9 |
cmp [ntfs_cur_read], eax |
jnz .done |
push eax |
mov eax, [ntfs_cur_offs] |
and eax, 0x400*8-1 |
bt dword [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, 0x18 |
add esi, [esi] |
.dump_subnode: |
test byte [esi+0Ch], 2 |
jnz .dump_subnode_done |
call .add_entry |
movzx eax, word [esi+8] |
add esi, eax |
jmp .dump_subnode |
.dump_subnode_done: |
inc [ntfs_cur_offs] |
test [ntfs_cur_offs], 0x400*8-1 |
jnz .dumploop |
mov [ntfs_cur_attr], 0xB0 |
push ecx edi |
mov edi, ntfs_bitmap_buf |
mov [ntfs_cur_buf], edi |
mov ecx, 0x400/4 |
xor eax, eax |
rep stosd |
pop edi ecx |
pop eax |
push [ntfs_cur_offs] |
inc eax |
mov [ntfs_cur_offs], eax |
mov [ntfs_cur_size], 2 |
push eax |
call ntfs_read_attr |
pop eax |
pop [ntfs_cur_offs] |
push eax |
jmp .dumploop |
.done: |
pop eax |
pop edx |
mov ebx, [edx+4] |
pop edx |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
mov [esp+1Ch], eax |
mov [esp+10h], ebx |
popad |
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, dword [ntfs_bitmap_buf+0x20] |
; or al, 0x10 |
mov eax, 0x10 |
stosd |
scasd |
push edx |
mov eax, dword [ntfs_bitmap_buf] |
mov edx, dword [ntfs_bitmap_buf+4] |
call ntfs_datetime_to_bdfe |
mov eax, dword [ntfs_bitmap_buf+0x18] |
mov edx, dword [ntfs_bitmap_buf+0x1C] |
call ntfs_datetime_to_bdfe |
mov eax, dword [ntfs_bitmap_buf+8] |
mov edx, dword [ntfs_bitmap_buf+0xC] |
call ntfs_datetime_to_bdfe |
pop edx |
xor eax, eax |
stosd |
stosd |
mov al, '.' |
push edi ecx |
lea ecx, [esi+1] |
test byte [edi-0x24], 1 |
jz @f |
rep stosw |
pop ecx |
xor eax, eax |
stosw |
pop edi |
add edi, 520 |
ret |
@@: |
rep stosb |
pop ecx |
xor eax, eax |
stosb |
pop edi |
add edi, 264 |
.ret: |
ret |
.add_entry: |
; do not return DOS 8.3 names |
cmp byte [esi+0x51], 2 |
jz .ret |
; do not return system files |
; ... note that there will be no bad effects if system files also were reported ... |
cmp dword [esi], 0x10 |
jb .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+0x50] |
add esi, 0x52 |
test byte [edi-0x24], 1 |
jz .ansi |
shr ecx, 1 |
rep movsd |
adc ecx, ecx |
rep movsw |
and word [edi], 0 |
pop edi |
add edi, 520 |
pop esi ecx |
ret |
.ansi: |
jecxz .skip |
@@: |
lodsw |
call uni2ansi_char |
stosb |
loop @b |
.skip: |
xor al, al |
stosb |
pop edi |
add edi, 264 |
pop esi ecx |
ret |
ntfs_direntry_to_bdfe: |
mov [edi+4], eax ; ANSI/UNICODE name |
mov eax, [esi+48h] |
test eax, 0x10000000 |
jz @f |
and eax, not 0x10000000 |
or al, 0x10 |
@@: |
stosd |
scasd |
push edx |
mov eax, [esi+0x18] |
mov edx, [esi+0x1C] |
call ntfs_datetime_to_bdfe |
mov eax, [esi+0x30] |
mov edx, [esi+0x34] |
call ntfs_datetime_to_bdfe |
mov eax, [esi+0x20] |
mov edx, [esi+0x24] |
call ntfs_datetime_to_bdfe |
pop edx |
mov eax, [esi+0x40] |
stosd |
mov eax, [esi+0x44] |
stosd |
ret |
iglobal |
_24 dd 24 |
_60 dd 60 |
_10000000 dd 10000000 |
days400year dd 365*400+100-4+1 |
days100year dd 365*100+25-1 |
days4year dd 365*4+1 |
days1year dd 365 |
months dd 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
months2 dd 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
_400 dd 400 |
_100 dd 100 |
endg |
ntfs_datetime_to_bdfe: |
; edx:eax = number of 100-nanosecond intervals since January 1, 1601, in UTC |
push eax |
mov eax, edx |
xor edx, edx |
div [_10000000] |
xchg eax, [esp] |
div [_10000000] |
pop edx |
.sec: |
; edx:eax = number of seconds since January 1, 1601 |
push eax |
mov eax, edx |
xor edx, edx |
div [_60] |
xchg eax, [esp] |
div [_60] |
mov [edi], dl |
pop edx |
; edx:eax = number of minutes |
div [_60] |
mov [edi+1], dl |
; eax = number of hours (note that 2^64/(10^7*60*60) < 2^32) |
xor edx, edx |
div [_24] |
mov [edi+2], dl |
mov [edi+3], byte 0 |
; eax = number of days since January 1, 1601 |
xor edx, edx |
div [days400year] |
imul eax, 400 |
add eax, 1601 |
mov [edi+6], ax |
mov eax, edx |
xor edx, edx |
div [days100year] |
cmp al, 4 |
jnz @f |
dec eax |
add edx, [days100year] |
@@: |
imul eax, 100 |
add [edi+6], ax |
mov eax, edx |
xor edx, edx |
div [days4year] |
shl eax, 2 |
add [edi+6], ax |
mov eax, edx |
xor edx, edx |
div [days1year] |
cmp al, 4 |
jnz @f |
dec eax |
add edx, [days1year] |
@@: |
add [edi+6], ax |
push esi edx |
mov esi, months |
movzx eax, word [edi+6] |
test al, 3 |
jnz .noleap |
xor edx, edx |
push eax |
div [_400] |
pop eax |
test edx, edx |
jz .leap |
xor edx, edx |
div [_100] |
test edx, edx |
jz .noleap |
.leap: |
mov esi, months2 |
.noleap: |
pop edx |
xor eax, eax |
inc eax |
@@: |
sub edx, [esi] |
jb @f |
add esi, 4 |
inc eax |
jmp @b |
@@: |
add edx, [esi] |
pop esi |
inc edx |
mov [edi+4], dl |
mov [edi+5], al |
add edi, 8 |
ret |
;---------------------------------------------------------------- |
; |
; ntfs_HdRewrite - write to NTFS hard disk |
; |
; esi points to filename |
; ebx ignored (reserved) |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = number of written bytes |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdRewrite: |
xor ebx, ebx |
mov eax, ERROR_UNSUPPORTED_FS |
ret |
;---------------------------------------------------------------- |
; |
; ntfs_HdWrite - write to NTFS hard disk |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = bytes written (maybe 0) |
; eax = 0 ok write or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdWrite: |
xor ebx, ebx |
mov eax, ERROR_UNSUPPORTED_FS |
ret |
;---------------------------------------------------------------- |
; |
; ntfs_HdSetFileEnd - set end of file on NTFS hard disk |
; |
; esi points to filename |
; ebx points to 64-bit number = new file size |
; ecx ignored (reserved) |
; edx ignored (reserved) |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdSetFileEnd: |
ntfs_HdSetFileInfo: |
;---------------------------------------------------------------- |
; |
; ntfs_HdDelete - delete file or empty folder from NTFS hard disk |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
ntfs_HdDelete: |
mov eax, ERROR_UNSUPPORTED_FS |
ret |
ntfs_HdGetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
push 2 |
pop eax |
ret |
@@: |
call ntfs_find_lfn |
jnc .doit |
push ERROR_FILE_NOT_FOUND |
pop eax |
cmp [hd_error], 0 |
jz @f |
mov al, 11 |
@@: |
ret |
.doit: |
push esi edi |
mov esi, eax |
mov edi, edx |
xor eax, eax |
call ntfs_direntry_to_bdfe |
pop edi esi |
xor eax, eax |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs/parse_fn.inc |
---|
0,0 → 1,236 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;------------------------------------------------------------------------- |
; |
; File path partial substitution (according to configuration) |
; |
; |
; SPraid |
; |
;------------------------------------------------------------------------- |
$Revision $ |
iglobal |
; pointer to memory for path replace table, |
; size of one record is 128 bytes: 64 bytes for search pattern + 64 bytes for replace string |
; start with one entry: sys -> <sysdir> |
full_file_name_table dd sysdir_name |
.size dd 1 |
tmp_file_name_size dd 1 |
endg |
uglobal |
; Parser_params will initialize: sysdir_name = "sys", sysdir_path = <sysdir> |
sysdir_name rb 64 |
sysdir_path rb 64 |
tmp_file_name_table dd ? |
endg |
; use bx_from_load and init system directory /sys |
proc Parser_params |
locals |
buff db 4 dup(?) ; for test cd |
endl |
mov eax, [OS_BASE+0x10000+bx_from_load] |
mov ecx, sysdir_path |
mov [ecx-64], dword 'sys' |
cmp al, 'r'; if ram disk |
jnz @f |
mov [ecx], dword 'RD/?' |
mov [ecx+3], byte ah |
mov [ecx+4], byte 0 |
ret |
@@: |
cmp al, 'm'; if ram disk |
jnz @f |
mov [ecx], dword 'CD?/'; if cd disk {m} |
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 .not_found_cd |
lea edx, [buff] |
pushad |
stdcall read_file, read_firstapp, edx, 0, 4 |
popad |
cmp [edx], dword 'MENU' |
jne .next_cd |
jmp .ok |
@@: |
sub al, 49 |
mov [ecx], dword 'HD?/'; if hard disk |
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 |
.ok: |
.not_found_cd: |
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 |
uglobal |
def_val_1 db 0 |
endg |
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 |
@@: |
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 |
.stop_parse: |
xor eax, eax |
ret |
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 |
; 1) allocate temporary buffer in stack |
sub esp, 64 |
; 2) save second part of name to temporary buffer |
push esi |
lea esi, [esp+4] ; esi->tmp buffer |
xchg esi, edi ; edi->tmp buffer, esi->source |
@@: |
lodsb |
stosb |
test al, al |
jnz @b |
; 3) copy first part of name to destination |
pop esi |
mov edi, ebx |
@@: |
lodsb |
test al, al |
jz @f |
stosb |
jmp @b |
@@: |
; 4) restore second part of name from temporary buffer to destination |
; (may cause overflow) |
lea edx, [ebx+64] ; limit of destination |
mov esi, esp |
@@: |
cmp edi, edx |
jae .overflow |
lodsb |
stosb |
test al, al |
jnz @b |
; all is OK |
add esp, 64 ; CF is cleared |
ret |
.overflow: |
; name is too long |
add esp, 64 |
stc |
ret |
endp |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fs |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/drivers/i8254x.asm |
---|
0,0 → 1,809 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; i8254x driver for KolibriOS ;; |
;; ;; |
;; based on i8254x.asm from baremetal os ;; |
;; ;; |
;; Written by hidnplayr (hidnplayr@gmail.com) ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; TODO: make better use of the available descriptors |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
MAX_PKT_SIZE = 16384 ; Maximum packet size |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include '../struct.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
; Register list |
REG_CTRL = 0x0000 ; Control Register |
REG_STATUS = 0x0008 ; Device Status Register |
REG_CTRLEXT = 0x0018 ; Extended Control Register |
REG_MDIC = 0x0020 ; MDI Control Register |
REG_FCAL = 0x0028 ; Flow Control Address Low |
REG_FCAH = 0x002C ; Flow Control Address High |
REG_FCT = 0x0030 ; Flow Control Type |
REG_VET = 0x0038 ; VLAN Ether Type |
REG_ICR = 0x00C0 ; Interrupt Cause Read |
REG_ITR = 0x00C4 ; Interrupt Throttling Register |
REG_ICS = 0x00C8 ; Interrupt Cause Set Register |
REG_IMS = 0x00D0 ; Interrupt Mask Set/Read Register |
REG_IMC = 0x00D8 ; Interrupt Mask Clear Register |
REG_RCTL = 0x0100 ; Receive Control Register |
REG_FCTTV = 0x0170 ; Flow Control Transmit Timer Value |
REG_TXCW = 0x0178 ; Transmit Configuration Word |
REG_RXCW = 0x0180 ; Receive Configuration Word |
REG_TCTL = 0x0400 ; Transmit Control Register |
REG_TIPG = 0x0410 ; Transmit Inter Packet Gap |
REG_LEDCTL = 0x0E00 ; LED Control |
REG_PBA = 0x1000 ; Packet Buffer Allocation |
REG_RDBAL = 0x2800 ; RX Descriptor Base Address Low |
REG_RDBAH = 0x2804 ; RX Descriptor Base Address High |
REG_RDLEN = 0x2808 ; RX Descriptor Length |
REG_RDH = 0x2810 ; RX Descriptor Head |
REG_RDT = 0x2818 ; RX Descriptor Tail |
REG_RDTR = 0x2820 ; RX Delay Timer Register |
REG_RXDCTL = 0x3828 ; RX Descriptor Control |
REG_RADV = 0x282C ; RX Int. Absolute Delay Timer |
REG_RSRPD = 0x2C00 ; RX Small Packet Detect Interrupt |
REG_TXDMAC = 0x3000 ; TX DMA Control |
REG_TDBAL = 0x3800 ; TX Descriptor Base Address Low |
REG_TDBAH = 0x3804 ; TX Descriptor Base Address High |
REG_TDLEN = 0x3808 ; TX Descriptor Length |
REG_TDH = 0x3810 ; TX Descriptor Head |
REG_TDT = 0x3818 ; TX Descriptor Tail |
REG_TIDV = 0x3820 ; TX Interrupt Delay Value |
REG_TXDCTL = 0x3828 ; TX Descriptor Control |
REG_TADV = 0x382C ; TX Absolute Interrupt Delay Value |
REG_TSPMT = 0x3830 ; TCP Segmentation Pad & Min Threshold |
REG_RXCSUM = 0x5000 ; RX Checksum Control |
; Register list for i8254x |
I82542_REG_RDTR = 0x0108 ; RX Delay Timer Register |
I82542_REG_RDBAL = 0x0110 ; RX Descriptor Base Address Low |
I82542_REG_RDBAH = 0x0114 ; RX Descriptor Base Address High |
I82542_REG_RDLEN = 0x0118 ; RX Descriptor Length |
I82542_REG_RDH = 0x0120 ; RDH for i82542 |
I82542_REG_RDT = 0x0128 ; RDT for i82542 |
I82542_REG_TDBAL = 0x0420 ; TX Descriptor Base Address Low |
I82542_REG_TDBAH = 0x0424 ; TX Descriptor Base Address Low |
I82542_REG_TDLEN = 0x0428 ; TX Descriptor Length |
I82542_REG_TDH = 0x0430 ; TDH for i82542 |
I82542_REG_TDT = 0x0438 ; TDT for i82542 |
; CTRL - Control Register (0x0000) |
CTRL_FD = 0x00000001 ; Full Duplex |
CTRL_LRST = 0x00000008 ; Link Reset |
CTRL_ASDE = 0x00000020 ; Auto-speed detection |
CTRL_SLU = 0x00000040 ; Set Link Up |
CTRL_ILOS = 0x00000080 ; Invert Loss of Signal |
CTRL_SPEED_MASK = 0x00000300 ; Speed selection |
CTRL_SPEED_SHIFT = 8 |
CTRL_FRCSPD = 0x00000800 ; Force Speed |
CTRL_FRCDPLX = 0x00001000 ; Force Duplex |
CTRL_SDP0_DATA = 0x00040000 ; SDP0 data |
CTRL_SDP1_DATA = 0x00080000 ; SDP1 data |
CTRL_SDP0_IODIR = 0x00400000 ; SDP0 direction |
CTRL_SDP1_IODIR = 0x00800000 ; SDP1 direction |
CTRL_RST = 0x04000000 ; Device Reset |
CTRL_RFCE = 0x08000000 ; RX Flow Ctrl Enable |
CTRL_TFCE = 0x10000000 ; TX Flow Ctrl Enable |
CTRL_VME = 0x40000000 ; VLAN Mode Enable |
CTRL_PHY_RST = 0x80000000 ; PHY reset |
; STATUS - Device Status Register (0x0008) |
STATUS_FD = 0x00000001 ; Full Duplex |
STATUS_LU = 0x00000002 ; Link Up |
STATUS_TXOFF = 0x00000010 ; Transmit paused |
STATUS_TBIMODE = 0x00000020 ; TBI Mode |
STATUS_SPEED_MASK = 0x000000C0 ; Link Speed setting |
STATUS_SPEED_SHIFT = 6 |
STATUS_ASDV_MASK = 0x00000300 ; Auto Speed Detection |
STATUS_ASDV_SHIFT = 8 |
STATUS_PCI66 = 0x00000800 ; PCI bus speed |
STATUS_BUS64 = 0x00001000 ; PCI bus width |
STATUS_PCIX_MODE = 0x00002000 ; PCI-X mode |
STATUS_PCIXSPD_MASK = 0x0000C000 ; PCI-X speed |
STATUS_PCIXSPD_SHIFT = 14 |
; CTRL_EXT - Extended Device Control Register (0x0018) |
CTRLEXT_PHY_INT = 0x00000020 ; PHY interrupt |
CTRLEXT_SDP6_DATA = 0x00000040 ; SDP6 data |
CTRLEXT_SDP7_DATA = 0x00000080 ; SDP7 data |
CTRLEXT_SDP6_IODIR = 0x00000400 ; SDP6 direction |
CTRLEXT_SDP7_IODIR = 0x00000800 ; SDP7 direction |
CTRLEXT_ASDCHK = 0x00001000 ; Auto-Speed Detect Chk |
CTRLEXT_EE_RST = 0x00002000 ; EEPROM reset |
CTRLEXT_SPD_BYPS = 0x00008000 ; Speed Select Bypass |
CTRLEXT_RO_DIS = 0x00020000 ; Relaxed Ordering Dis. |
CTRLEXT_LNKMOD_MASK = 0x00C00000 ; Link Mode |
CTRLEXT_LNKMOD_SHIFT = 22 |
; MDIC - MDI Control Register (0x0020) |
MDIC_DATA_MASK = 0x0000FFFF ; Data |
MDIC_REG_MASK = 0x001F0000 ; PHY Register |
MDIC_REG_SHIFT = 16 |
MDIC_PHY_MASK = 0x03E00000 ; PHY Address |
MDIC_PHY_SHIFT = 21 |
MDIC_OP_MASK = 0x0C000000 ; Opcode |
MDIC_OP_SHIFT = 26 |
MDIC_R = 0x10000000 ; Ready |
MDIC_I = 0x20000000 ; Interrupt Enable |
MDIC_E = 0x40000000 ; Error |
; ICR - Interrupt Cause Read (0x00c0) |
ICR_TXDW = 0x00000001 ; TX Desc Written back |
ICR_TXQE = 0x00000002 ; TX Queue Empty |
ICR_LSC = 0x00000004 ; Link Status Change |
ICR_RXSEQ = 0x00000008 ; RX Sence Error |
ICR_RXDMT0 = 0x00000010 ; RX Desc min threshold reached |
ICR_RXO = 0x00000040 ; RX Overrun |
ICR_RXT0 = 0x00000080 ; RX Timer Interrupt |
ICR_MDAC = 0x00000200 ; MDIO Access Complete |
ICR_RXCFG = 0x00000400 |
ICR_PHY_INT = 0x00001000 ; PHY Interrupt |
ICR_GPI_SDP6 = 0x00002000 ; GPI on SDP6 |
ICR_GPI_SDP7 = 0x00004000 ; GPI on SDP7 |
ICR_TXD_LOW = 0x00008000 ; TX Desc low threshold hit |
ICR_SRPD = 0x00010000 ; Small RX packet detected |
; RCTL - Receive Control Register (0x0100) |
RCTL_EN = 0x00000002 ; Receiver Enable |
RCTL_SBP = 0x00000004 ; Store Bad Packets |
RCTL_UPE = 0x00000008 ; Unicast Promiscuous Enabled |
RCTL_MPE = 0x00000010 ; Xcast Promiscuous Enabled |
RCTL_LPE = 0x00000020 ; Long Packet Reception Enable |
RCTL_LBM_MASK = 0x000000C0 ; Loopback Mode |
RCTL_LBM_SHIFT = 6 |
RCTL_RDMTS_MASK = 0x00000300 ; RX Desc Min Threshold Size |
RCTL_RDMTS_SHIFT = 8 |
RCTL_MO_MASK = 0x00003000 ; Multicast Offset |
RCTL_MO_SHIFT = 12 |
RCTL_BAM = 0x00008000 ; Broadcast Accept Mode |
RCTL_BSIZE_MASK = 0x00030000 ; RX Buffer Size |
RCTL_BSIZE_SHIFT = 16 |
RCTL_VFE = 0x00040000 ; VLAN Filter Enable |
RCTL_CFIEN = 0x00080000 ; CFI Enable |
RCTL_CFI = 0x00100000 ; Canonical Form Indicator Bit |
RCTL_DPF = 0x00400000 ; Discard Pause Frames |
RCTL_PMCF = 0x00800000 ; Pass MAC Control Frames |
RCTL_BSEX = 0x02000000 ; Buffer Size Extension |
RCTL_SECRC = 0x04000000 ; Strip Ethernet CRC |
; TCTL - Transmit Control Register (0x0400) |
TCTL_EN = 0x00000002 ; Transmit Enable |
TCTL_PSP = 0x00000008 ; Pad short packets |
TCTL_SWXOFF = 0x00400000 ; Software XOFF Transmission |
; PBA - Packet Buffer Allocation (0x1000) |
PBA_RXA_MASK = 0x0000FFFF ; RX Packet Buffer |
PBA_RXA_SHIFT = 0 |
PBA_TXA_MASK = 0xFFFF0000 ; TX Packet Buffer |
PBA_TXA_SHIFT = 16 |
; Flow Control Type |
FCT_TYPE_DEFAULT = 0x8808 |
; === TX Descriptor fields === |
; TX Packet Length (word 2) |
TXDESC_LEN_MASK = 0x0000ffff |
; TX Descriptor CMD field (word 2) |
TXDESC_IDE = 0x80000000 ; Interrupt Delay Enable |
TXDESC_VLE = 0x40000000 ; VLAN Packet Enable |
TXDESC_DEXT = 0x20000000 ; Extension |
TXDESC_RPS = 0x10000000 ; Report Packet Sent |
TXDESC_RS = 0x08000000 ; Report Status |
TXDESC_IC = 0x04000000 ; Insert Checksum |
TXDESC_IFCS = 0x02000000 ; Insert FCS |
TXDESC_EOP = 0x01000000 ; End Of Packet |
; TX Descriptor STA field (word 3) |
TXDESC_TU = 0x00000008 ; Transmit Underrun |
TXDESC_LC = 0x00000004 ; Late Collision |
TXDESC_EC = 0x00000002 ; Excess Collisions |
TXDESC_DD = 0x00000001 ; Descriptor Done |
; === RX Descriptor fields === |
; RX Packet Length (word 2) |
RXDESC_LEN_MASK = 0x0000ffff |
; RX Descriptor STA field (word 3) |
RXDESC_PIF = 0x00000080 ; Passed In-exact Filter |
RXDESC_IPCS = 0x00000040 ; IP cksum calculated |
RXDESC_TCPCS = 0x00000020 ; TCP cksum calculated |
RXDESC_VP = 0x00000008 ; Packet is 802.1Q |
RXDESC_IXSM = 0x00000004 ; Ignore cksum indication |
RXDESC_EOP = 0x00000002 ; End Of Packet |
RXDESC_DD = 0x00000001 ; Descriptor Done |
virtual at ebx |
device: |
ETH_DEVICE |
.mmio_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.cur_tx dd ? |
.last_tx dd ? |
rb 0x100 - (($ - device) and 0xff) |
.rx_desc rd 256/8 |
rb 0x100 - (($ - device) and 0xff) |
.tx_desc rd 256/8 |
sizeof.device_struct = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax, [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte [device.pci_bus] |
jne .next |
cmp ah, byte [device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
.next: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte [eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte [eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base mmio addres of the PCI device |
PCI_find_mmio32 |
; Create virtual mapping of the physical memory |
push 1Bh ; PG_SW+PG_NOCACHE |
push 10000h ; size of the map |
push eax |
call MapIoMem |
mov [device.mmio_addr], eax |
; We've found the mmio address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.mmio_addr]:8 |
; Ok, the eth_device structure is ready, let's probe the device |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
call start_i8254x |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (device_list) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax, -1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device (if it really is I8254X) |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
DEBUGF 1,"Probe\n" |
PCI_make_bus_master |
; TODO: validate the device |
call read_mac |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
reset_dontstart: |
DEBUGF 1,"Reset\n" |
mov esi, [device.mmio_addr] |
or dword [esi + REG_CTRL], CTRL_RST ; reset device |
.loop: |
push esi |
xor esi, esi |
inc esi |
call Sleep |
pop esi |
test dword [esi + REG_CTRL], CTRL_RST |
jnz .loop |
mov dword [esi + REG_IMC], 0xffffffff ; Disable all interrupt causes |
mov eax, dword [esi + REG_ICR] ; Clear any pending interrupts |
mov dword [esi + REG_ITR], 0 ; Disable interrupt throttling logic |
mov dword [esi + REG_PBA], 0x00000030 ; PBA: set the RX buffer size to 48KB (TX buffer is calculated as 64-RX buffer) |
mov dword [esi + REG_RDTR], 0 ; RDTR: set no delay |
mov dword [esi + REG_TXCW], 0x08008060 ; TXCW: set ANE, TxConfigWord (Half/Full duplex, Next Page Reqest) |
mov eax, [esi + REG_CTRL] |
or eax, 1 shl 6 + 1 shl 5 |
and eax, not (1 shl 3 + 1 shl 7 + 1 shl 30 + 1 shl 31) |
mov dword [esi + REG_CTRL], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS |
lea edi, [esi + 0x5200] ; MTA: reset |
mov eax, 0xffffffff |
stosd |
stosd |
stosd |
stosd |
stdcall KernelAlloc, 48*1024 |
mov dword [device.rx_desc + 16], eax |
GetRealAddr |
mov dword [device.rx_desc], eax |
mov dword [device.rx_desc + 4], 0 |
lea eax, [device.rx_desc] |
GetRealAddr |
mov dword [esi + REG_RDBAL], eax ; Receive Descriptor Base Address Low |
mov dword [esi + REG_RDBAH], 0 ; Receive Descriptor Base Address High |
mov dword [esi + REG_RDLEN], (1 * 128) ; Receive Descriptor Length |
mov dword [esi + REG_RDH], 0 ; Receive Descriptor Head |
mov dword [esi + REG_RDT], 1 ; Receive Descriptor Tail |
mov dword [esi + REG_RCTL], RCTL_EN or RCTL_SBP or RCTL_BAM or RCTL_SECRC or RCTL_UPE or RCTL_MPE |
; Receiver Enable, Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet, Promiscuous mode |
mov dword [device.tx_desc], 0 |
mov dword [device.tx_desc + 4], 0 |
mov dword [device.tx_desc + 16], 0 |
lea eax, [device.tx_desc] |
GetRealAddr |
mov dword [esi + REG_TDBAL], eax ; Transmit Descriptor Base Address Low |
mov dword [esi + REG_TDBAH], 0 ; Transmit Descriptor Base Address High |
mov dword [esi + REG_TDLEN], (1 * 128) ; Transmit Descriptor Length |
mov dword [esi + REG_TDH], 0 ; Transmit Descriptor Head |
mov dword [esi + REG_TDT], 0 ; Transmit Descriptor Tail |
mov dword [esi + REG_TCTL], 0x010400fa ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision |
mov dword [esi + REG_TIPG], 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6 |
xor eax, eax |
ret |
align 4 |
reset: |
call reset_dontstart |
start_i8254x: |
xor eax, eax |
mov [esi + REG_RDTR], eax ; Clear the Receive Delay Timer Register |
mov [esi + REG_RADV], eax ; Clear the Receive Interrupt Absolute Delay Timer |
mov [esi + REG_RSRPD], eax ; Clear the Receive Small Packet Detect Interrupt |
; or eax, 1 shl 0 + 1 shl 7 ; TXDW + RXT0 |
mov eax, 1+4+16 ;;;; hack! |
mov [esi + REG_IMS], eax ; Enable interrupt types |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
xor eax, eax |
ret |
align 4 |
read_mac: |
DEBUGF 1,"Read MAC\n" |
mov esi, [device.mmio_addr] |
mov eax, [esi+0x5400] ; RAL |
test eax, eax |
jz .try_eeprom |
mov dword [device.mac], eax |
mov eax, [esi+0x5404] ; RAH |
mov word [device.mac+4], ax |
jmp .mac_ok |
.try_eeprom: |
mov dword [esi+0x14], 0x00000001 |
mov eax, [esi+0x14] |
shr eax, 16 |
mov word [device.mac], ax |
mov dword [esi+0x14], 0x00000101 |
mov eax, [esi+0x14] |
shr eax, 16 |
mov word [device.mac+2], ax |
mov dword [esi+0x14], 0x00000201 |
mov eax, [esi+0x14] |
shr eax, 16 |
mov word [device.mac+4], ax |
.mac_ok: |
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp + 8], 1514 |
ja .fail |
cmp dword [esp + 8], 60 |
jb .fail |
; Program the descriptor (use legacy mode) |
lea edi, [device.tx_desc] ; Transmit Descriptor Base Address |
mov dword [edi + 16], eax ; Store the data location (for driver) |
GetRealAddr ; |
mov dword [edi], eax ; Real addr (for i8254x) |
mov dword [edi + 4], 0x00000000 ; |
mov ecx, [esp + 8] |
or ecx, 1 shl 24 + 1 shl 25 + 1 shl 27 ; EOP + IFCS + RS |
mov dword [edi + 8], ecx ; Packet size |
mov dword [edi + 12], 0x00000000 |
; Tell i8254x wich descriptor(s) we programmed |
mov edi, [device.mmio_addr] |
mov dword [edi + REG_TDH], 0 ; TDH - Transmit Descriptor Head |
mov dword [edi + REG_TDT], 1 ; TDT - Transmit Descriptor Tail |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp + 8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
ret 8 |
.fail: |
DEBUGF 1,"Send failed\n" |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
;------------------------------------------- |
; Find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
mov edi, [device.mmio_addr] |
mov eax, [edi + REG_ICR] |
test eax, eax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, eax |
;--------- |
; RX done? |
test eax, ICR_RXDMT0 |
jz .no_rx |
push eax ebx |
push .retaddr |
; Get last descriptor addr |
lea esi, [device.rx_desc] |
cmp byte [esi + 12], 0 ; Check status field |
je .retaddr |
movzx ecx, word [esi + 8] ; Get the packet length |
DEBUGF 2,"got %u bytes\n", ecx |
push ecx |
push dword [esi + 16] ; Get packet pointer |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
; allocate new descriptor |
stdcall KernelAlloc, 48*1024 |
mov dword [esi + 16], eax |
GetRealAddr |
mov dword [esi], eax |
; reset descriptor status |
mov esi, [device.mmio_addr] |
mov dword [esi + REG_RDH], 0x00000000 ; Receive Descriptor Head |
mov dword [esi + REG_RDT], 0x00000001 ; Receive Descriptor Tail |
jmp Eth_input |
.retaddr: |
pop ebx eax |
.no_rx: |
;-------------- |
; Link Changed? |
test eax, ICR_LSC |
jz .no_link |
DEBUGF 2,"Link Changed\n" |
.no_link: |
;--------------- |
; Transmit done? |
test eax, ICR_TXDW |
jz .no_tx |
DEBUGF 2,"Transmit done\n" |
lea edi, [device.tx_desc] ; Transmit Descriptor Base Address |
push dword [edi + 16] ; Store the data location (for driver) |
call KernelFree |
.no_tx: |
.fail: |
ret |
; End of code |
section '.data' data readable writable align 16 |
align 4 |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'I8254X',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/RTL8139.asm |
---|
0,0 → 1,1122 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Realtek 8139 driver for KolibriOS ;; |
;; ;; |
;; based on RTL8139.asm driver for menuetos ;; |
;; and realtek8139.asm for SolarOS by Eugen Brasoveanu ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
RBLEN = 3 ; Receive buffer size: 0==8K 1==16k 2==32k 3==64k |
NUM_TX_DESC = 4 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
REG_IDR0 = 0x00 |
REG_MAR0 = 0x08 ; multicast filter register 0 |
REG_MAR4 = 0x0c ; multicast filter register 4 |
REG_TSD0 = 0x10 ; transmit status of descriptor |
REG_TSAD0 = 0x20 ; transmit start address of descriptor |
REG_RBSTART = 0x30 ; RxBuffer start address |
REG_COMMAND = 0x37 ; command register |
REG_CAPR = 0x38 ; current address of packet read (word) R/W |
REG_IMR = 0x3c ; interrupt mask register |
REG_ISR = 0x3e ; interrupt status register |
REG_TXCONFIG = 0x40 ; transmit configuration register |
REG_RXCONFIG = 0x44 ; receive configuration register 0 |
REG_MPC = 0x4c ; missed packet counter |
REG_9346CR = 0x50 ; serial eeprom 93C46 command register |
REG_CONFIG1 = 0x52 ; configuration register 1 |
REG_MSR = 0x58 |
REG_CONFIG4 = 0x5a ; configuration register 4 |
REG_HLTCLK = 0x5b ; undocumented halt clock register |
REG_BMCR = 0x62 ; basic mode control register |
REG_ANAR = 0x66 ; auto negotiation advertisement register |
REG_9346CR_WE = 11b shl 6 |
BIT_RUNT = 4 ; total packet length < 64 bytes |
BIT_LONG = 3 ; total packet length > 4k |
BIT_CRC = 2 ; crc error occured |
BIT_FAE = 1 ; frame alignment error occured |
BIT_ROK = 0 ; received packet is ok |
BIT_RST = 4 ; reset bit |
BIT_RE = 3 ; receiver enabled |
BIT_TE = 2 ; transmitter enabled |
BUFE = 1 ; rx buffer is empty, no packet stored |
BIT_ISR_TOK = 2 ; transmit ok |
BIT_ISR_RER = 1 ; receive error interrupt |
BIT_ISR_ROK = 0 ; receive ok |
BIT_TX_MXDMA = 8 ; Max DMA burst size per Tx DMA burst |
BIT_TXRR = 4 ; Tx Retry count 16+(TXRR*16) |
BIT_RXFTH = 13 ; Rx fifo threshold |
BIT_RBLEN = 11 ; Ring buffer length indicator |
BIT_RX_MXDMA = 8 ; Max DMA burst size per Rx DMA burst |
BIT_NOWRAP = 7 ; transfered data wrapping |
BIT_9356SEL = 6 ; eeprom selector 9346/9356 |
BIT_AER = 5 ; accept error packets |
BIT_AR = 4 ; accept runt packets |
BIT_AB = 3 ; accept broadcast packets |
BIT_AM = 2 ; accept multicast packets |
BIT_APM = 1 ; accept physical match packets |
BIT_AAP = 0 ; accept all packets |
BIT_93C46_EEM1 = 7 ; RTL8139 eeprom operating mode1 |
BIT_93C46_EEM0 = 6 ; RTL8139 eeprom operating mode0 |
BIT_93C46_EECS = 3 ; chip select |
BIT_93C46_EESK = 2 ; serial data clock |
BIT_93C46_EEDI = 1 ; serial data input |
BIT_93C46_EEDO = 0 ; serial data output |
BIT_LWACT = 4 ; see REG_CONFIG1 |
BIT_SLEEP = 1 ; sleep bit at older chips |
BIT_PWRDWN = 0 ; power down bit at older chips |
BIT_PMEn = 0 ; power management enabled |
BIT_LWPTN = 2 ; see REG_CONFIG4 |
BIT_ERTXTH = 16 ; early TX threshold |
BIT_TOK = 15 ; transmit ok |
BIT_OWN = 13 ; tx DMA operation is completed |
BIT_ANE = 12 ; auto negotiation enable |
BIT_TXFD = 8 ; 100base-T full duplex |
BIT_TX = 7 ; 100base-T |
BIT_10FD = 6 ; 10base-T full duplex |
BIT_10 = 5 ; 10base-T |
BIT_SELECTOR = 0 ; binary encoded selector CSMA/CD=00001 |
BIT_IFG1 = 25 |
BIT_IFG0 = 24 |
TXRR = 8 ; total retries = 16+(TXRR*16) |
TX_MXDMA = 6 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=2048 |
ERTXTH = 8 ; in unit of 32 bytes e.g:(8*32)=256 |
RX_MXDMA = 7 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=unlimited |
RXFTH = 7 ; 0=16 1=32 2=64 3=128 4=256 5=512 6=1024 7=no threshold |
RX_CONFIG = (RBLEN shl BIT_RBLEN) or \ |
(RX_MXDMA shl BIT_RX_MXDMA) or \ |
(1 shl BIT_NOWRAP) or \ |
(RXFTH shl BIT_RXFTH) or\ |
(1 shl BIT_AB) or \ ; Accept broadcast packets |
(1 shl BIT_APM) or \ ; Accept physical match packets |
(1 shl BIT_AER) or \ ; Accept error packets |
(1 shl BIT_AR) or \ ; Accept Runt packets (smaller then 64 bytes) |
(1 shl BIT_AM) ; Accept multicast packets |
RX_BUFFER_SIZE = (8192 shl RBLEN);+16 |
MAX_ETH_FRAME_SIZE = 1514 |
EE_93C46_REG_ETH_ID = 7 ; MAC offset |
EE_93C46_READ_CMD = (6 shl 6) ; 110b + 6bit address |
EE_93C56_READ_CMD = (6 shl 8) ; 110b + 8bit address |
EE_93C46_CMD_LENGTH = 9 ; start bit + cmd + 6bit address |
EE_93C56_CMD_LENGTH = 11 ; start bit + cmd + 8bit ddress |
VER_RTL8139 = 1100000b |
VER_RTL8139A = 1110000b |
VER_RTL8139AG = 1110100b |
VER_RTL8139B = 1111000b |
VER_RTL8130 = VER_RTL8139B |
VER_RTL8139C = 1110100b |
VER_RTL8100 = 1111010b |
VER_RTL8100B = 1110101b |
VER_RTL8139D = VER_RTL8100B |
VER_RTL8139CP = 1110110b |
VER_RTL8101 = 1110111b |
IDX_RTL8139 = 0 |
IDX_RTL8139A = 1 |
IDX_RTL8139B = 2 |
IDX_RTL8139C = 3 |
IDX_RTL8100 = 4 |
IDX_RTL8139D = 5 |
IDX_RTL8139D = 6 |
IDX_RTL8101 = 7 |
ISR_SERR = 1 shl 15 |
ISR_TIMEOUT = 1 shl 14 |
ISR_LENCHG = 1 shl 13 |
ISR_FIFOOVW = 1 shl 6 |
ISR_PUN = 1 shl 5 |
ISR_RXOVW = 1 shl 4 |
ISR_TER = 1 shl 3 |
ISR_TOK = 1 shl 2 |
ISR_RER = 1 shl 1 |
ISR_ROK = 1 shl 0 |
INTERRUPT_MASK = ISR_ROK or \ |
ISR_RXOVW or \ |
ISR_PUN or \ |
ISR_FIFOOVW or \ |
ISR_LENCHG or \ |
ISR_TOK or \ |
ISR_TER |
TSR_OWN = 1 shl 13 |
TSR_TUN = 1 shl 14 |
TSR_TOK = 1 shl 15 |
TSR_CDH = 1 shl 28 |
TSR_OWC = 1 shl 29 |
TSR_TABT = 1 shl 30 |
TSR_CRS = 1 shl 31 |
virtual at ebx |
device: |
ETH_DEVICE |
.rx_buffer dd ? |
.rx_data_offset dd ? |
.io_addr dd ? |
.curr_tx_desc db ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.hw_ver_id db ? |
.TX_DESC rd NUM_TX_DESC |
.size = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2, "Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
mov ax, [eax+1] ; get the pci bus and device numbers |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 2, "Hooking into device, dev:%x, bus:%x, irq:%x, I/O addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Allocate the receive buffer |
stdcall CreateRingBuffer, dword (RX_BUFFER_SIZE), dword PG_SW |
test eax, eax |
jz .err |
mov [device.rx_buffer], eax |
; Ok, the eth_device structure is ready, let's probe the device |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 2, "Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2, "Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, [device.rx_buffer] |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (RTL8139_LIST) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax, -1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device (if it really is RTL8139) |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
DEBUGF 2, "Probing %s device\n", my_service |
PCI_make_bus_master |
; get chip version |
set_io 0 |
set_io REG_TXCONFIG + 2 |
in ax, dx |
shr ah, 2 |
shr ax, 6 |
and al, 01111111b |
; now find it in our array |
mov ecx, HW_VER_ARRAY_SIZE-1 |
.chip_ver_loop: |
cmp al, [hw_ver_array + ecx] |
je .chip_ver_found |
dec ecx |
jns .chip_ver_loop |
.unknown: |
mov ecx, 8 |
.chip_ver_found: |
cmp ecx, 8 |
ja .unknown |
mov [device.hw_ver_id], cl |
mov ecx, [crosslist+ecx*4] |
mov [device.name], ecx |
DEBUGF 2, "Chip version: %s\n", ecx |
; wake up the chip |
set_io 0 |
set_io REG_HLTCLK |
mov al, 'R' ; run the clock |
out dx, al |
; unlock config and BMCR registers |
set_io REG_9346CR |
mov al, (1 shl BIT_93C46_EEM1) or (1 shl BIT_93C46_EEM0) |
out dx, al |
; enable power management |
set_io REG_CONFIG1 |
in al, dx |
cmp [device.hw_ver_id], IDX_RTL8139B |
jae .new_chip |
; wake up older chips |
and al, not ((1 shl BIT_SLEEP) or (1 shl BIT_PWRDWN)) |
out dx, al |
jmp .finish_wake_up |
; set LWAKE pin to active high (default value). |
; it is for Wake-On-LAN functionality of some motherboards. |
; this signal is used to inform the motherboard to execute a wake-up process. |
; only at newer chips. |
.new_chip: |
or al, (1 shl BIT_PMEn) |
and al, not (1 shl BIT_LWACT) |
out dx, al |
set_io REG_CONFIG4 |
in al, dx |
and al, not (1 shl BIT_LWPTN) |
out dx, al |
; lock config and BMCR registers |
.finish_wake_up: |
xor al, al |
set_io 0 |
set_io REG_9346CR |
out dx, al |
DEBUGF 2, "done!\n" |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; reset: Set up all registers and descriptors, clear some values |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
reset: |
DEBUGF 2, "Reset\n" |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 1, "Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1, "\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
; reset chip |
DEBUGF 1, "Resetting chip\n" |
set_io 0 |
set_io REG_COMMAND |
mov al, 1 shl BIT_RST |
out dx, al |
mov cx, 1000 ; wait no longer for the reset |
.wait_for_reset: |
in al, dx |
test al, 1 shl BIT_RST |
jz .reset_completed ; RST remains 1 during reset |
dec cx |
jns .wait_for_reset |
DEBUGF 1, "Reset timeout!\n" |
.reset_completed: |
; unlock config and BMCR registers |
set_io REG_9346CR |
mov al, (1 shl BIT_93C46_EEM1) or (1 shl BIT_93C46_EEM0) |
out dx, al |
; initialize multicast registers (no filtering) |
mov eax, 0xffffffff |
set_io REG_MAR0 |
out dx, eax |
set_io REG_MAR4 |
out dx, eax |
; enable Rx/Tx |
mov al, (1 shl BIT_RE) or (1 shl BIT_TE) |
set_io REG_COMMAND |
out dx, al |
; Rxbuffer size, unlimited dma burst, no wrapping, no rx threshold |
; accept broadcast packets, accept physical match packets |
mov ax, RX_CONFIG |
set_io REG_RXCONFIG |
out dx, ax |
; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 |
mov eax, (TX_MXDMA shl BIT_TX_MXDMA) or (TXRR shl BIT_TXRR) or BIT_IFG1 or BIT_IFG0 |
set_io REG_TXCONFIG |
out dx, eax |
; enable auto negotiation |
set_io REG_BMCR |
in ax, dx |
or ax, (1 shl BIT_ANE) |
out dx, ax |
; set auto negotiation advertisement |
set_io REG_ANAR |
in ax, dx |
or ax, (1 shl BIT_SELECTOR) or (1 shl BIT_10) or (1 shl BIT_10FD) or (1 shl BIT_TX) or (1 shl BIT_TXFD) |
out dx, ax |
; lock config and BMCR registers |
xor eax, eax |
set_io REG_9346CR |
out dx, al |
; init RX/TX pointers |
mov [device.rx_data_offset], eax |
mov [device.curr_tx_desc], al |
; set_io REG_CAPR |
; out dx, ax |
; clear packet/byte counters |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
; clear missing packet counter |
set_io REG_MPC |
out dx, eax |
; set RxBuffer address, init RX buffer offset |
mov eax, [device.rx_buffer] |
mov dword[eax], 0 ; clear receive flags for first packet (really needed??) |
DEBUGF 2, "RX buffer virtual addr=0x%x\n", eax |
GetRealAddr |
DEBUGF 2, "RX buffer real addr=0x%x\n", eax |
set_io REG_RBSTART |
out dx, eax |
; Read MAC address |
call read_mac |
; enable interrupts |
set_io 0 |
set_io REG_IMR |
mov ax, INTERRUPT_MASK |
out dx, ax |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
call cable |
; Indicate that we have successfully reset the card |
xor eax, eax |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 1, "\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 1, "To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], MAX_ETH_FRAME_SIZE |
ja .fail |
cmp dword [esp+8], 60 |
jb .fail |
; check if we own the current discriptor |
set_io 0 |
set_io REG_TSD0 |
movzx ecx, [device.curr_tx_desc] |
shl ecx, 2 |
add edx, ecx |
in eax, dx |
test eax, (1 shl BIT_OWN) |
jz .wait_to_send |
.send_packet: |
; get next descriptor |
inc [device.curr_tx_desc] |
and [device.curr_tx_desc], NUM_TX_DESC-1 |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx+4], 0 |
; Set the buffer address |
set_io REG_TSAD0 |
mov eax, [esp+4] |
mov [device.TX_DESC+ecx], eax |
GetRealAddr |
out dx, eax |
; And the size of the buffer |
set_io REG_TSD0 |
mov eax, [esp+8] |
or eax, (ERTXTH shl BIT_ERTXTH) ; Early threshold |
out dx, eax |
DEBUGF 1, "Packet Sent!\n" |
xor eax, eax |
ret 8 |
.wait_to_send: |
DEBUGF 1, "Waiting for timeout\n" |
push edx |
mov esi, 30 |
stdcall Sleep |
pop edx |
in ax, dx |
test ax, (1 shl BIT_OWN) |
jnz .send_packet |
pusha |
call reset ; if chip hung, reset it |
popa |
jmp .send_packet |
.fail: |
DEBUGF 1, "failed!\n" |
stdcall KernelFree, [esp+4] |
or eax, -1 |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1, "\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io REG_ISR |
in ax, dx ; Get interrupt status |
out dx, ax ; send it back to ACK |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1, "Device: %x Status: %x\n", ebx, ax |
;---------------------------------------------------- |
; Received packet ok? |
test ax, ISR_ROK |
jz @f |
push ax |
.receive: |
set_io 0 |
set_io REG_COMMAND |
in al, dx |
test al, BUFE ; test if RX buffer is empty |
jnz .finish |
DEBUGF 1, "RX: " |
mov eax, [device.rx_buffer] |
add eax, [device.rx_data_offset] |
test byte [eax], (1 shl BIT_ROK) ; check if packet is ok |
jz .reset_rx |
; packet is ok, copy it |
movzx ecx, word [eax+2] ; packet length |
sub cx, 4 ; don't copy CRC |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc [device.packets_rx] |
DEBUGF 1, "Received %u bytes\n", ecx |
push ebx eax ecx |
stdcall KernelAlloc, ecx ; Allocate a buffer to put packet into |
pop ecx |
test eax, eax ; Test if we allocated succesfully |
jz .abort |
mov edi, eax ; Where we will copy too |
mov esi, [esp] ; The buffer we will copy from |
add esi, 4 ; Dont copy CRC |
push dword .abort ; Kernel will return to this address after EthReceiver |
push ecx edi ; Save buffer pointer and size, to pass to kernel |
.copy: |
shr ecx, 1 |
jnc .nb |
movsb |
.nb: |
shr ecx, 1 |
jnc .nw |
movsw |
.nw: |
jz .nd |
rep movsd |
.nd: |
jmp Eth_input ; Send it to kernel |
.abort: |
pop eax ebx |
; update eth_data_start_offset |
movzx eax, word [eax+2] ; packet length |
add eax, [device.rx_data_offset] |
add eax, 4+3 ; packet header is 4 bytes long + dword alignment |
and eax, not 3 ; dword alignment |
cmp eax, RX_BUFFER_SIZE |
jb .no_wrap |
DEBUGF 2, "Wrapping" |
sub eax, RX_BUFFER_SIZE |
.no_wrap: |
mov [device.rx_data_offset], eax |
DEBUGF 1, "New RX ptr: %d\n", eax |
set_io 0 |
set_io REG_CAPR ; update 'Current Address of Packet Read register' |
sub eax, 0x10 ; value 0x10 is a constant for CAPR |
out dx , ax |
jmp .receive ; check for multiple packets |
.reset_rx: |
test byte [eax], (1 shl BIT_CRC) |
jz .no_crc_error |
DEBUGF 2, "\nCRC error!\n" |
.no_crc_error: |
test byte [eax], (1 shl BIT_FAE) |
jz .no_fae_error |
DEBUGF 1, "\nFrame alignment error!\n" |
.no_fae_error: |
DEBUGF 1, "Reset RX\n" |
in al, dx ; read command register |
push ax |
and al, not (1 shl BIT_RE) ; Clear the RE bit |
out dx, al |
pop ax |
out dx, al ; write original command back |
add edx, REG_RXCONFIG - REG_COMMAND ; Restore RX configuration |
mov ax, RX_CONFIG |
out dx, ax |
.finish: |
pop ax |
;---------------------------------------------------- |
; Transmit ok / Transmit error |
@@: |
test ax, ISR_TOK + ISR_TER |
jz @f |
push ax |
mov ecx, (NUM_TX_DESC-1)*4 |
.txdescloop: |
set_io 0 |
set_io REG_TSD0 |
add edx, ecx |
in eax, dx |
test eax, TSR_OWN ; DMA operation completed |
jz .notthisone |
cmp [device.TX_DESC+ecx], 0 |
je .notthisone |
; .notxd: |
; test eax, TSR_TUN |
; jz .nobun |
; DEBUGF 2, "TX: FIFO Buffer underrun!\n" |
; |
; .nobun: |
; test eax, TSR_OWC |
; jz .noowc |
; DEBUGF 2, "TX: OWC!\n" |
; |
; .noowc: |
; test eax, TSR_TABT |
; jz .notabt |
; DEBUGF 2, "TX: TABT!\n" |
; |
; .notabt: |
; test eax, TSR_CRS |
; jz .nocsl |
; DEBUGF 2, "TX: Carrier Sense Lost!\n" |
; |
; .nocsl: |
DEBUGF 1, "TX OK: free buffer %x\n", [device.TX_DESC+ecx]:8 |
push ecx ebx |
stdcall KernelFree, [device.TX_DESC+ecx] |
pop ebx ecx |
mov [device.TX_DESC+ecx], 0 |
.notthisone: |
sub ecx, 4 |
ja .txdescloop |
pop ax |
;---------------------------------------------------- |
; Rx buffer overflow ? |
@@: |
test ax, ISR_RXOVW |
jz @f |
push ax |
DEBUGF 2, "RX-buffer overflow!\n" |
set_io 0 |
set_io REG_ISR |
mov ax, ISR_FIFOOVW or ISR_RXOVW |
out dx, ax |
pop ax |
;---------------------------------------------------- |
; Packet underrun? |
@@: |
test ax, ISR_PUN |
jz @f |
DEBUGF 2, "Packet underrun!\n" |
;---------------------------------------------------- |
; Receive FIFO overflow ? |
@@: |
test ax, ISR_FIFOOVW |
jz @f |
push ax |
DEBUGF 2, "RX fifo overflow!\n" |
set_io 0 |
set_io REG_ISR |
mov ax, ISR_FIFOOVW or ISR_RXOVW |
out dx, ax |
pop ax |
;---------------------------------------------------- |
; Something about Cable changed ? |
@@: |
test ax, ISR_LENCHG |
jz .fail |
call cable |
.fail: |
DEBUGF 2, "\n" |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Update Cable status ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
cable: |
DEBUGF 1, "Updating Cable status\n" |
set_io 0 |
set_io REG_MSR |
in al, dx |
test al, 1 shl 2 ; 0 = link ok 1 = link fail |
jnz .notconnected |
test al, 1 shl 3 ; 0 = 100 Mbps 1 = 10 Mbps |
jnz .10mbps |
.100mbps: |
mov [device.state], ETH_LINK_100M |
call NetLinkChanged |
ret |
.10mbps: |
mov [device.state], ETH_LINK_10M |
call NetLinkChanged |
ret |
.notconnected: |
mov [device.state], ETH_LINK_DOWN |
call NetLinkChanged |
ret |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Write MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
write_mac: ; in: mac pushed onto stack (as 3 words) |
DEBUGF 2, "Writing MAC: " |
; disable all in command registers |
set_io 0 |
set_io REG_9346CR |
xor eax, eax |
out dx, al |
set_io REG_IMR |
xor eax, eax |
out dx, ax |
set_io REG_ISR |
mov eax, -1 |
out dx, ax |
; enable writing |
set_io REG_9346CR |
mov eax, REG_9346CR_WE |
out dx, al |
; write the mac ... |
set_io REG_IDR0 |
pop eax |
out dx, eax |
set_io REG_IDR0+4 |
xor eax, eax |
pop ax |
out dx, eax |
; disable writing |
set_io REG_9346CR |
xor eax, eax |
out dx, al |
DEBUGF 2, "ok!\n" |
; Notice this procedure does not ret, but continues to read_mac instead. |
;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Read MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;; |
read_mac: |
DEBUGF 2, "Reading MAC: " |
set_io 0 |
lea edi, [device.mac] |
in eax, dx |
stosd |
add edx, 4 |
in ax, dx |
stosw |
DEBUGF 2, "%x-%x-%x-%x-%x-%x\n",[edi-6]:2,[edi-5]:2,[edi-4]:2,[edi-3]:2,[edi-2]:2,[edi-1]:2 |
ret |
; End of code |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'RTL8139',0 ; max 16 chars include zero |
device_1 db 'Realtek 8139',0 |
device_2 db 'Realtek 8139A',0 |
device_3 db 'Realtek 8139B',0 |
device_4 db 'Realtek 8139C',0 |
device_5 db 'Realtek 8100',0 |
device_6 db 'Realtek 8139D',0 |
device_7 db 'Realtek 8139CP',0 |
device_8 db 'Realtek 8101',0 |
device_unknown db 'Unknown RTL8139 clone', 0 |
crosslist: |
dd device_1 |
dd device_2 |
dd device_3 |
dd device_4 |
dd device_5 |
dd device_6 |
dd device_7 |
dd device_8 |
dd device_unknown |
hw_ver_array: ; This array is used by the probe routine to find out wich version of the RTL8139 we are working with |
db VER_RTL8139 |
db VER_RTL8139A |
db VER_RTL8139B |
db VER_RTL8139C |
db VER_RTL8100 |
db VER_RTL8139D |
db VER_RTL8139CP |
db VER_RTL8101 |
db 0 |
HW_VER_ARRAY_SIZE = $-hw_ver_array |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/bus/mii.inc |
---|
0,0 → 1,160 |
; Generic MII registers. |
MII_BMCR = 0x00 ; Basic mode control register |
MII_BMSR = 0x01 ; Basic mode status register |
MII_PHYSID1 = 0x02 ; PHYS ID 1 |
MII_PHYSID2 = 0x03 ; PHYS ID 2 |
MII_ADVERTISE = 0x04 ; Advertisement control reg |
MII_LPA = 0x05 ; Link partner ability reg |
MII_EXPANSION = 0x06 ; Expansion register |
MII_CTRL1000 = 0x09 ; 1000BASE-T control |
MII_STAT1000 = 0x0a ; 1000BASE-T status |
MII_ESTATUS = 0x0f ; Extended Status |
MII_DCOUNTER = 0x12 ; Disconnect counter |
MII_FCSCOUNTER = 0x13 ; False carrier counter |
MII_NWAYTEST = 0x14 ; N-way auto-neg test reg |
MII_RERRCOUNTER = 0x15 ; Receive error counter |
MII_SREVISION = 0x16 ; Silicon revision |
MII_RESV1 = 0x17 ; Reserved... |
MII_LBRERROR = 0x18 ; Lpback, rx, bypass error |
MII_PHYADDR = 0x19 ; PHY address |
MII_RESV2 = 0x1a ; Reserved... |
MII_TPISTATUS = 0x1b ; TPI status for 10mbps |
MII_NCONFIG = 0x1c ; Network interface config |
; Basic mode control register. |
BMCR_RESV = 0x003f ; Unused... |
BMCR_SPEED1000 = 0x0040 ; MSB of Speed (1000) |
BMCR_CTST = 0x0080 ; Collision test |
BMCR_FULLDPLX = 0x0100 ; Full duplex |
BMCR_ANRESTART = 0x0200 ; Auto negotiation restart |
BMCR_ISOLATE = 0x0400 ; Disconnect DP83840 from MII |
BMCR_PDOWN = 0x0800 ; Powerdown the DP83840 |
BMCR_ANENABLE = 0x1000 ; Enable auto negotiation |
BMCR_SPEED100 = 0x2000 ; Select 100Mbps |
BMCR_LOOPBACK = 0x4000 ; TXD loopback bits |
BMCR_RESET = 0x8000 ; Reset the DP83840 |
; Basic mode status register. |
BMSR_ERCAP = 0x0001 ; Ext-reg capability |
BMSR_JCD = 0x0002 ; Jabber detected |
BMSR_LSTATUS = 0x0004 ; Link status |
BMSR_ANEGCAPABLE = 0x0008 ; Able to do auto-negotiation |
BMSR_RFAULT = 0x0010 ; Remote fault detected |
BMSR_ANEGCOMPLETE = 0x0020 ; Auto-negotiation complete |
BMSR_RESV = 0x00c0 ; Unused... |
BMSR_ESTATEN = 0x0100 ; Extended Status in R15 |
BMSR_100HALF2 = 0x0200 ; Can do 100BASE-T2 HDX |
BMSR_100FULL2 = 0x0400 ; Can do 100BASE-T2 FDX |
BMSR_10HALF = 0x0800 ; Can do 10mbps, half-duplex |
BMSR_10FULL = 0x1000 ; Can do 10mbps, full-duplex |
BMSR_100HALF = 0x2000 ; Can do 100mbps, half-duplex |
BMSR_100FULL = 0x4000 ; Can do 100mbps, full-duplex |
BMSR_100BASE4 = 0x8000 ; Can do 100mbps, 4k packets |
; Advertisement control register. |
ADVERTISE_SLCT = 0x001f ; Selector bits |
ADVERTISE_CSMA = 0x0001 ; Only selector supported |
ADVERTISE_10HALF = 0x0020 ; Try for 10mbps half-duplex |
ADVERTISE_1000XFULL = 0x0020 ; Try for 1000BASE-X full-duplex |
ADVERTISE_10FULL = 0x0040 ; Try for 10mbps full-duplex |
ADVERTISE_1000XHALF = 0x0040 ; Try for 1000BASE-X half-duplex |
ADVERTISE_100HALF = 0x0080 ; Try for 100mbps half-duplex |
ADVERTISE_1000XPAUSE = 0x0080 ; Try for 1000BASE-X pause |
ADVERTISE_100FULL = 0x0100 ; Try for 100mbps full-duplex |
ADVERTISE_1000XPSE_ASYM = 0x0100 ; Try for 1000BASE-X asym pause |
ADVERTISE_100BASE4 = 0x0200 ; Try for 100mbps 4k packets |
ADVERTISE_PAUSE_CAP = 0x0400 ; Try for pause |
ADVERTISE_PAUSE_ASYM = 0x0800 ; Try for asymetric pause |
ADVERTISE_RESV = 0x1000 ; Unused... |
ADVERTISE_RFAULT = 0x2000 ; Say we can detect faults |
ADVERTISE_LPACK = 0x4000 ; Ack link partners response |
ADVERTISE_NPAGE = 0x8000 ; Next page bit |
ADVERTISE_FULL = (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) |
ADVERTISE_ALL = (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) |
; Link partner ability register. |
LPA_SLCT = 0x001f ; Same as advertise selector |
LPA_10HALF = 0x0020 ; Can do 10mbps half-duplex |
LPA_1000XFULL = 0x0020 ; Can do 1000BASE-X full-duplex |
LPA_10FULL = 0x0040 ; Can do 10mbps full-duplex |
LPA_1000XHALF = 0x0040 ; Can do 1000BASE-X half-duplex |
LPA_100HALF = 0x0080 ; Can do 100mbps half-duplex |
LPA_1000XPAUSE = 0x0080 ; Can do 1000BASE-X pause |
LPA_100FULL = 0x0100 ; Can do 100mbps full-duplex |
LPA_1000XPAUSE_ASYM = 0x0100 ; Can do 1000BASE-X pause asym |
LPA_100BASE4 = 0x0200 ; Can do 100mbps 4k packets |
LPA_PAUSE_CAP = 0x0400 ; Can pause |
LPA_PAUSE_ASYM = 0x0800 ; Can pause asymetrically |
LPA_RESV = 0x1000 ; Unused... |
LPA_RFAULT = 0x2000 ; Link partner faulted |
LPA_LPACK = 0x4000 ; Link partner acked us |
LPA_NPAGE = 0x8000 ; Next page bit |
LPA_DUPLEX = (LPA_10FULL or LPA_100FULL) |
LPA_100 = (LPA_100FULL or LPA_100HALF or LPA_100BASE4) |
; Expansion register for auto-negotiation. |
EXPANSION_NWAY = 0x0001 ; Can do N-way auto-nego |
EXPANSION_LCWP = 0x0002 ; Got new RX page code word |
EXPANSION_ENABLENPAGE = 0x0004 ; This enables npage words |
EXPANSION_NPCAPABLE = 0x0008 ; Link partner supports npage |
EXPANSION_MFAULTS = 0x0010 ; Multiple faults detected |
EXPANSION_RESV = 0xffe0 ; Unused... |
ESTATUS_1000_TFULL = 0x2000 ; Can do 1000BT Full |
ESTATUS_1000_THALF = 0x1000 ; Can do 1000BT Half |
; N-way test register. |
NWAYTEST_RESV1 = 0x00ff ; Unused... |
NWAYTEST_LOOPBACK = 0x0100 ; Enable loopback for N-way |
NWAYTEST_RESV2 = 0xfe00 ; Unused... |
; 1000BASE-T Control register |
ADVERTISE_1000FULL = 0x0200 ; Advertise 1000BASE-T full duplex |
ADVERTISE_1000HALF = 0x0100 ; Advertise 1000BASE-T half duplex |
; 1000BASE-T Status register |
LPA_1000LOCALRXOK = 0x2000 ; Link partner local receiver status |
LPA_1000REMRXOK = 0x1000 ; Link partner remote receiver status |
LPA_1000FULL = 0x0800 ; Link partner 1000BASE-T full duplex |
LPA_1000HALF = 0x0400 ; Link partner 1000BASE-T half duplex |
; Flow control flags |
FLOW_CTRL_TX = 0x01 |
FLOW_CTRL_RX = 0x02 |
if used mii_link_ok |
align 4 |
mii_link_ok: |
DEBUGF 1, "mii_link_ok\n" |
; First do a dummy read to latch some MII phys |
mov ecx, MII_BMSR |
call mdio_read |
mov ecx, MII_BMSR |
call mdio_read |
and ax, BMSR_LSTATUS |
DEBUGF 1, "link status=0x%x\n", ax |
ret |
end if |
/kernel/branches/net/drivers/bus/pci.inc |
---|
0,0 → 1,132 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; PCI Bus defines |
PCI_HEADER_TYPE = 0x0e ; 8 bit |
PCI_BASE_ADDRESS_0 = 0x10 ; 32 bit |
PCI_BASE_ADDRESS_1 = 0x14 ; 32 bits |
PCI_BASE_ADDRESS_2 = 0x18 ; 32 bits |
PCI_BASE_ADDRESS_3 = 0x1c ; 32 bits |
PCI_BASE_ADDRESS_4 = 0x20 ; 32 bits |
PCI_BASE_ADDRESS_5 = 0x24 ; 32 bits |
PCI_BASE_ADDRESS_SPACE_IO = 0x01 |
PCI_BASE_ADDRESS_IO_MASK = 0xFFFFFFFC |
PCI_BASE_ADDRESS_MEM_MASK = 0xFFFFFFF0 |
; PCI programming |
PCI_VENDOR_ID = 0x00 ; 16 bit |
PCI_DEVICE_ID = 0x02 ; 16 bits |
PCI_REG_COMMAND = 0x4 ; command register |
PCI_REG_STATUS = 0x6 ; status register |
PCI_REVISION_ID = 0x08 ; 8 bits |
PCI_REG_LATENCY = 0xd ; latency timer register |
PCI_REG_CAP_PTR = 0x34 ; capabilities pointer |
PCI_REG_IRQ = 0x3c |
PCI_REG_CAPABILITY_ID = 0x0 ; capapility ID in pm register block |
PCI_REG_PM_STATUS = 0x4 ; power management status register |
PCI_REG_PM_CTRL = 0x4 ; power management control register |
PCI_BIT_PIO = 1 ; bit0: io space control |
PCI_BIT_MMIO = 2 ; bit1: memory space control |
PCI_BIT_MASTER = 4 ; bit2: device acts as a PCI master |
macro PCI_find_io { |
local .check, .inc, .got |
xor eax, eax |
mov esi, PCI_BASE_ADDRESS_0 |
.check: |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi |
test eax, PCI_BASE_ADDRESS_IO_MASK |
jz .inc |
test eax, PCI_BASE_ADDRESS_SPACE_IO |
jz .inc |
and eax, PCI_BASE_ADDRESS_IO_MASK |
jmp .got |
.inc: |
add esi, 4 |
cmp esi, PCI_BASE_ADDRESS_5 |
jbe .check |
xor eax, eax |
.got: |
mov [device.io_addr], eax |
} |
macro PCI_find_mmio32 { |
local .check, .inc, .got |
mov esi, PCI_BASE_ADDRESS_0 |
.check: |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi |
test eax, PCI_BASE_ADDRESS_SPACE_IO ; mmio address? |
jnz .inc |
test eax, 100b ; 64 bit? |
jnz .inc |
and eax, not 1111b |
jmp .got |
.inc: |
add esi, 4 |
cmp esi, PCI_BASE_ADDRESS_5 |
jbe .check |
xor eax, eax |
.got: |
mov [device.mmio_addr], eax |
} |
macro PCI_find_irq { |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_IRQ |
mov [device.irq_line], al |
} |
macro PCI_find_rev { |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REVISION_ID |
mov [device.revision], al |
} |
macro PCI_make_bus_master bus, dev { |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_REG_COMMAND |
or al, PCI_BIT_MASTER |
stdcall PciWrite32, [device.pci_bus], [device.pci_dev], PCI_REG_COMMAND, eax |
} |
macro PCI_adjust_latency min { |
local .not |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY |
cmp al, min |
ja .not |
mov al, min |
stdcall PciWrite8, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY, eax |
.not: |
} |
/kernel/branches/net/drivers/pcnet32.asm |
---|
0,0 → 1,1570 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; AMD PCnet driver for KolibriOS ;; |
;; ;; |
;; By hidnplayr & clevermouse ;; |
;; ;; |
;; Based on the PCnet32 driver for MenuetOS, by Jarek Pelczar ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
MAX_DEVICES = 4 |
MAX_ETH_FRAME_SIZE = 1514 |
TX_RING_SIZE = 4 |
RX_RING_SIZE = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
PORT_AUI = 0x00 |
PORT_10BT = 0x01 |
PORT_GPSI = 0x02 |
PORT_MII = 0x03 |
PORT_PORTSEL = 0x03 |
PORT_ASEL = 0x04 |
PORT_100 = 0x40 |
PORT_FD = 0x80 |
DMA_MASK = 0xffffffff |
LOG_TX_BUFFERS = 2 ; FIXME |
LOG_RX_BUFFERS = 2 |
TX_RING_MOD_MASK = (TX_RING_SIZE-1) |
TX_RING_LEN_BITS = (LOG_TX_BUFFERS shl 12) |
RX_RING_MOD_MASK = (RX_RING_SIZE-1) |
RX_RING_LEN_BITS = (LOG_RX_BUFFERS shl 4) |
PKT_BUF_SZ = 1544 |
WIO_RDP = 0x10 |
WIO_RAP = 0x12 |
WIO_RESET = 0x14 |
WIO_BDP = 0x16 |
DWIO_RDP = 0x10 |
DWIO_RAP = 0x14 |
DWIO_RESET = 0x18 |
DWIO_BDP = 0x1C |
; CSR registers |
CSR_CSR = 0x00 |
CSR_IAB0 = 0x01 |
CSR_IAB1 = 0x02 |
CSR_IMR = 0x03 |
CSR_TFEAT = 0x04 |
CSR_EXTCTL1 = 0x05 |
CSR_DTBLLEN = 0x06 |
CSR_EXTCTL2 = 0x07 |
CSR_MAR0 = 0x08 |
CSR_MAR1 = 0x09 |
CSR_MAR2 = 0x0A |
CSR_MAR3 = 0x0B |
CSR_PAR0 = 0x0C |
CSR_PAR1 = 0x0D |
CSR_PAR2 = 0x0E |
CSR_MODE = 0x0F |
CSR_RXADDR0 = 0x18 |
CSR_RXADDR1 = 0x19 |
CSR_TXADDR0 = 0x1E |
CSR_TXADDR1 = 0x1F |
CSR_TXPOLL = 0x2F |
CSR_RXPOLL = 0x31 |
CSR_RXRINGLEN = 0x4C |
CSR_TXRINGLEN = 0x4E |
CSR_DMACTL = 0x50 |
CSR_BUSTIMER = 0x52 |
CSR_MEMERRTIMEO = 0x64 |
CSR_ONNOWMISC = 0x74 |
CSR_ADVFEAT = 0x7A |
CSR_MACCFG = 0x7D |
CSR_CHIPID0 = 0x58 |
CSR_CHIPID1 = 0x59 |
; Control and Status Register (CSR0) |
CSR_INIT = 1 shl 0 |
CSR_START = 1 shl 1 |
CSR_STOP = 1 shl 2 |
CSR_TX = 1 shl 3 |
CSR_TXON = 1 shl 4 |
CSR_RXON = 1 shl 5 |
CSR_INTEN = 1 shl 6 |
CSR_INTR = 1 shl 7 |
CSR_IDONE = 1 shl 8 |
CSR_TINT = 1 shl 9 |
CSR_RINT = 1 shl 10 |
CSR_MERR = 1 shl 11 |
CSR_MISS = 1 shl 12 |
CSR_CERR = 1 shl 13 |
; Interrupt masks and deferral control (CSR3) |
IMR_BSWAP = 0x0004 |
IMR_ENMBA = 0x0008 ; enable modified backoff alg |
IMR_DXMT2PD = 0x0010 |
IMR_LAPPEN = 0x0020 ; lookahead packet processing enb |
IMR_DXSUFLO = 0x0040 ; disable TX stop on underflow |
IMR_IDONE = 0x0100 |
IMR_TINT = 0x0200 |
IMR_RINT = 0x0400 |
IMR_MERR = 0x0800 |
IMR_MISS = 0x1000 |
IMR = IMR_IDONE ; IMR_TINT + IMR_RINT + IMR_MERR + IMR_MISS ;+ IMR_IDONE |
; Test and features control (CSR4) |
TFEAT_TXSTRTMASK = 0x0004 |
TFEAT_TXSTRT = 0x0008 |
TFEAT_RXCCOFLOWM = 0x0010 ; Rx collision counter oflow |
TFEAT_RXCCOFLOW = 0x0020 |
TFEAT_UINT = 0x0040 |
TFEAT_UINTREQ = 0x0080 |
TFEAT_MISSOFLOWM = 0x0100 |
TFEAT_MISSOFLOW = 0x0200 |
TFEAT_STRIP_FCS = 0x0400 |
TFEAT_PAD_TX = 0x0800 |
TFEAT_TXDPOLL = 0x1000 |
TFEAT_DMAPLUS = 0x4000 |
; Extended control and interrupt 1 (CSR5) |
EXTCTL1_SPND = 0x0001 ; suspend |
EXTCTL1_MPMODE = 0x0002 ; magic packet mode |
EXTCTL1_MPENB = 0x0004 ; magic packet enable |
EXTCTL1_MPINTEN = 0x0008 ; magic packet interrupt enable |
EXTCTL1_MPINT = 0x0010 ; magic packet interrupt |
EXTCTL1_MPPLBA = 0x0020 ; magic packet phys. logical bcast |
EXTCTL1_EXDEFEN = 0x0040 ; excessive deferral interrupt enb. |
EXTCTL1_EXDEF = 0x0080 ; excessive deferral interrupt |
EXTCTL1_SINTEN = 0x0400 ; system interrupt enable |
EXTCTL1_SINT = 0x0800 ; system interrupt |
EXTCTL1_LTINTEN = 0x4000 ; last TX interrupt enb |
EXTCTL1_TXOKINTD = 0x8000 ; TX OK interrupt disable |
; RX/TX descriptor len (CSR6) |
DTBLLEN_RLEN = 0x0F00 |
DTBLLEN_TLEN = 0xF000 |
; Extended control and interrupt 2 (CSR7) |
EXTCTL2_MIIPDTINTE = 0x0001 |
EXTCTL2_MIIPDTINT = 0x0002 |
EXTCTL2_MCCIINTE = 0x0004 |
EXTCTL2_MCCIINT = 0x0008 |
EXTCTL2_MCCINTE = 0x0010 |
EXTCTL2_MCCINT = 0x0020 |
EXTCTL2_MAPINTE = 0x0040 |
EXTCTL2_MAPINT = 0x0080 |
EXTCTL2_MREINTE = 0x0100 |
EXTCTL2_MREINT = 0x0200 |
EXTCTL2_STINTE = 0x0400 |
EXTCTL2_STINT = 0x0800 |
EXTCTL2_RXDPOLL = 0x1000 |
EXTCTL2_RDMD = 0x2000 |
EXTCTL2_RXFRTG = 0x4000 |
EXTCTL2_FASTSPNDE = 0x8000 |
; Mode (CSR15) |
MODE_RXD = 0x0001 ; RX disable |
MODE_TXD = 0x0002 ; TX disable |
MODE_LOOP = 0x0004 ; loopback enable |
MODE_TXCRCD = 0x0008 |
MODE_FORCECOLL = 0x0010 |
MODE_RETRYD = 0x0020 |
MODE_INTLOOP = 0x0040 |
MODE_PORTSEL = 0x0180 |
MODE_RXVPAD = 0x2000 |
MODE_RXNOBROAD = 0x4000 |
MODE_PROMISC = 0x8000 |
; BCR (Bus Control Registers) |
BCR_MMRA = 0x00 ; Master Mode Read Active |
BCR_MMW = 0x01 ; Master Mode Write Active |
BCR_MISCCFG = 0x02 |
BCR_LED0 = 0x04 |
BCR_LED1 = 0x05 |
BCR_LED2 = 0x06 |
BCR_LED3 = 0x07 |
BCR_DUPLEX = 0x09 |
BCR_BUSCTL = 0x12 |
BCR_EECTL = 0x13 |
BCR_SSTYLE = 0x14 |
BCR_PCILAT = 0x16 |
BCR_PCISUBVENID = 0x17 |
BCR_PCISUBSYSID = 0x18 |
BCR_SRAMSIZE = 0x19 |
BCR_SRAMBOUND = 0x1A |
BCR_SRAMCTL = 0x1B |
BCR_MIICTL = 0x20 |
BCR_MIIADDR = 0x21 |
BCR_MIIDATA = 0x22 |
BCR_PCIVENID = 0x23 |
BCR_PCIPCAP = 0x24 |
BCR_DATA0 = 0x25 |
BCR_DATA1 = 0x26 |
BCR_DATA2 = 0x27 |
BCR_DATA3 = 0x28 |
BCR_DATA4 = 0x29 |
BCR_DATA5 = 0x2A |
BCR_DATA6 = 0x2B |
BCR_DATA7 = 0x2C |
BCR_ONNOWPAT0 = 0x2D |
BCR_ONNOWPAT1 = 0x2E |
BCR_ONNOWPAT2 = 0x2F |
BCR_PHYSEL = 0x31 |
; RX status register |
RXSTAT_BPE = 0x0080 ; bus parity error |
RXSTAT_ENP = 0x0100 ; end of packet |
RXSTAT_STP = 0x0200 ; start of packet |
RXSTAT_BUFF = 0x0400 ; buffer error |
RXSTAT_CRC = 0x0800 ; CRC error |
RXSTAT_OFLOW = 0x1000 ; rx overrun |
RXSTAT_FRAM = 0x2000 ; framing error |
RXSTAT_ERR = 0x4000 ; error summary |
RXSTAT_OWN = 0x8000 |
; TX status register |
TXSTAT_TRC = 0x0000000F ; transmit retries |
TXSTAT_RTRY = 0x04000000 ; retry |
TXSTAT_LCAR = 0x08000000 ; lost carrier |
TXSTAT_LCOL = 0x10000000 ; late collision |
TXSTAT_EXDEF = 0x20000000 ; excessive deferrals |
TXSTAT_UFLOW = 0x40000000 ; transmit underrun |
TXSTAT_BUFF = 0x80000000 ; buffer error |
TXCTL_OWN = 0x8000 |
TXCTL_ERR = 0x4000 ; error summary |
TXCTL_ADD_FCS = 0x2000 ; add FCS to pkt |
TXCTL_MORE_LTINT = 0x1000 |
TXCTL_ONE = 0x0800 |
TXCTL_DEF = 0x0400 |
TXCTL_STP = 0x0200 |
TXCTL_ENP = 0x0100 |
TXCTL_BPE = 0x0080 |
TXCTL_MBO = 0x0000F000 |
TXCTL_BUFSZ = 0x00000FFF |
; |
MAX_PHYS = 32 |
virtual at ebx |
device: |
ETH_DEVICE |
; device specific |
rb 0x100-(($ - device) and 0xff) ; align 256 |
.private: |
.mode_ dw ? |
.tlen_rlen dw ? |
.phys_addr dp ? |
.reserved dw ? |
.filter dq ? |
.rx_ring_phys dd ? |
.tx_ring_phys dd ? |
rb 0x100-(($ - device) and 0xff) ; align 256 |
.rx_ring rb RX_RING_SIZE * descriptor.size |
rb 0x100-(($ - device) and 0xff) ; align 256 |
.tx_ring rb TX_RING_SIZE * descriptor.size |
.cur_rx db ? |
.cur_tx db ? |
.last_tx db ? |
.options dd ? |
.full_duplex db ? |
.chip_version dw ? |
.mii db ? |
.ltint db ? |
.dxsuflo db ? |
.fset db ? |
.fdx db ? |
.io_addr dd ? |
.irq_line db ? |
.pci_bus dd ? |
.pci_dev dd ? |
.phy dw ? |
.read_csr dd ? |
.write_csr dd ? |
.read_bcr dd ? |
.write_bcr dd ? |
.read_rap dd ? |
.write_rap dd ? |
.sw_reset dd ? |
device_size = $ - device |
end virtual |
struc descriptor { |
.base dd ? |
.length dw ? |
.status dw ? |
.msg_length dw ? |
.misc dw ? |
.virtual dd ? |
.size: |
} |
virtual at 0 |
descriptor descriptor |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 1,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
mov esi, device_list |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device_size, .fail |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Ok, the eth_device structure is ready, let's probe the device |
; Because initialization fires IRQ, IRQ handler must be aware of this device |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
call probe ; this function will output in eax |
test eax, eax |
jnz .destroy ; If an error occured, exit |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
dec [devices] |
.err: |
DEBUGF 1,"Error, removing all data !\n" |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (RTL8139_LIST) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device (if it really is a PCnet device) |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
mov edx, [device.io_addr] |
call wio_reset |
xor ecx, ecx |
call wio_read_csr |
cmp eax, 4 |
jne .try_dwio |
; Try Word I/O |
mov ax, 88 |
add edx, WIO_RAP |
out dx, ax |
nop |
nop |
in ax, dx |
sub edx, WIO_RAP |
cmp ax, 88 |
jne .try_dwio |
call switch_to_wio |
jmp .L1 |
.try_dwio: |
call dwio_reset |
xor ecx, ecx |
call dwio_read_csr |
cmp eax, 4 |
jne .no_dev |
; Try Dword I/O |
add edx, DWIO_RAP |
mov eax, 88 |
out dx, eax |
nop |
nop |
in eax, dx |
sub edx, DWIO_RAP |
and eax, 0xffff |
cmp eax, 88 |
jne .no_dev |
call switch_to_dwio |
jmp .L1 |
.no_dev: |
DEBUGF 1,"PCnet device not found!\n" |
mov eax, 1 |
ret |
.L1: |
mov ecx, CSR_CHIPID0 |
call [device.read_csr] |
mov esi, eax |
shr esi, 12 |
and ax, 0xfff |
cmp ax, 3 |
jne .no_dev |
mov ecx, CSR_CHIPID1 |
call [device.read_csr] |
shl eax, 4 |
or eax, esi |
mov [device.chip_version], ax |
mov [device.fdx], 0 |
mov [device.mii], 0 |
mov [device.fset], 0 |
mov [device.dxsuflo], 0 |
mov [device.ltint], 0 |
cmp ax, 0x2420 |
je .L2 |
cmp ax, 0x2430 |
je .L2 |
mov [device.fdx], 1 |
cmp ax, 0x2621 |
je .L4 |
cmp ax, 0x2623 |
je .L5 |
cmp ax, 0x2624 |
je .L6 |
cmp ax, 0x2625 |
je .L7 |
cmp ax, 0x2626 |
je .L8 |
cmp ax, 0x2627 |
je .L9 |
DEBUGF 1,"Invalid chip rev\n" |
jmp .no_dev |
.L2: |
mov [device.name], device_l2 |
jmp .L10 |
.L4: |
mov [device.name], device_l4 |
; mov [device.fdx], 1 |
jmp .L10 |
.L5: |
mov [device.name], device_l5 |
; mov [device.fdx], 1 |
mov [device.mii], 1 |
mov [device.fset], 1 |
mov [device.ltint], 1 |
jmp .L10 |
.L6: |
mov [device.name], device_l6 |
; mov [device.fdx], 1 |
mov [device.mii], 1 |
mov [device.fset], 1 |
jmp .L10 |
.L7: |
mov [device.name], device_l7 |
; mov [device.fdx], 1 |
mov [device.mii], 1 |
jmp .L10 |
.L8: |
mov [device.name], device_l8 |
; mov [device.fdx], 1 |
mov ecx, CSR_RXPOLL |
call dword [device.read_bcr] |
call dword [device.write_bcr] |
jmp .L10 |
.L9: |
mov [device.name], device_l9 |
; mov [device.fdx], 1 |
mov [device.mii], 1 |
.L10: |
DEBUGF 1,"device name: %s\n", [device.name] |
cmp [device.fset], 1 |
jne .L11 |
mov ecx, BCR_BUSCTL |
call [device.read_bcr] |
or eax, 0x800 |
call [device.write_bcr] |
mov ecx, CSR_DMACTL |
call [device.read_csr] |
; and eax, 0xc00 |
; or eax, 0xc00 |
mov eax, 0xc00 |
call [device.write_csr] |
mov [device.dxsuflo],1 |
mov [device.ltint],1 |
.L11: |
PCI_make_bus_master |
mov [device.options], PORT_ASEL |
mov [device.mode_], MODE_RXD + MODE_TXD ; disable receive and transmit |
mov [device.tlen_rlen], (TX_RING_LEN_BITS or RX_RING_LEN_BITS) |
mov dword [device.filter], 0 |
mov dword [device.filter+4], 0 |
align 4 |
reset: |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
mov edx, [device.io_addr] |
call [device.sw_reset] |
; Switch pcnet32 to 32bit mode |
mov ecx, BCR_SSTYLE |
mov eax, 2 |
call [device.write_bcr] |
; set/reset autoselect bit |
mov ecx, BCR_MISCCFG |
call [device.read_bcr] |
and eax, not 2 |
test [device.options], PORT_ASEL |
jz @f |
or eax, 2 |
@@: |
call [device.write_bcr] |
; Handle full duplex setting |
cmp byte [device.full_duplex], 0 |
je .duplex_ok |
mov ecx, BCR_DUPLEX |
call [device.read_bcr] |
and eax, not 3 |
test [device.options], PORT_FD |
jz @f |
or eax, 1 |
cmp [device.options], PORT_FD or PORT_AUI |
jne .set_duplex |
or eax, 2 |
jmp .set_duplex |
@@: |
test [device.options], PORT_ASEL |
jz .set_duplex |
cmp [device.chip_version], 0x2627 |
jne .set_duplex |
or eax, 3 |
.set_duplex: |
mov ecx, BCR_DUPLEX |
call [device.write_bcr] |
.duplex_ok: |
; set/reset GPSI bit in test register |
mov ecx, 124 |
call [device.read_csr] |
mov ecx, [device.options] |
and ecx, PORT_PORTSEL |
cmp ecx, PORT_GPSI |
jne @f |
or eax, 0x10 |
@@: |
call [device.write_csr] |
cmp [device.mii], 0 |
je .L6 |
test [device.options], PORT_ASEL |
jnz .L6 |
mov ecx, BCR_MIICTL |
call [device.read_bcr] |
and eax, not 0x38 |
test [device.options], PORT_FD |
jz @f |
or eax, 0x10 |
@@: |
test [device.options], PORT_100 |
jz @f |
or eax, 0x08 |
@@: |
call [device.write_bcr] |
jmp .L9 |
.L6: |
test [device.options], PORT_ASEL |
jz .L9 |
mov ecx, BCR_MIICTL |
DEBUGF 1,"ASEL, enable auto-negotiation\n" |
call [device.read_bcr] |
and eax, not 0x98 |
or eax, 0x20 |
call [device.write_bcr] |
.L9: |
cmp [device.ltint], 0 |
je @f |
mov ecx, 5 |
call [device.read_csr] |
or eax, (1 shl 14) |
call [device.write_csr] |
@@: |
mov eax, [device.options] |
and eax, PORT_PORTSEL |
shl eax, 7 |
mov [device.mode_], ax |
mov dword [device.filter], -1 |
mov dword [device.filter+4], -1 |
;----------------------------- |
test [device.mii], 1 |
jz .no_mii |
mov [device.phy], 0 |
.mii_loop: |
mov ecx, MII_PHYSID1 |
call mdio_read |
cmp ax, 0xffff |
je .next |
DEBUGF 1, "0x%x\n", ax |
mov ecx, MII_PHYSID2 |
call mdio_read |
cmp ax, 0xffff |
je .next |
DEBUGF 1, "0x%x\n", ax |
jmp .got_phy |
cmp [device.phy], 31 |
jne .next |
mov ax, [device.chip_version] |
inc ax |
and ax, 0xfffe |
cmp ax, 0x2624 ; 79c971 & 79c972 have phantom phy at id 31 |
je .got_phy |
.next: |
inc [device.phy] |
cmp [device.phy], MAX_PHYS |
jb .mii_loop |
DEBUGF 1, "No PHY found!\n" |
or eax, -1 |
ret |
.got_phy: |
DEBUGF 1, "Found PHY at 0x%x\n", [device.phy]:4 |
.no_mii: |
;----------------------------------------------- |
call read_mac |
lea esi, [device.mac] |
lea edi, [device.phys_addr] |
movsd |
movsw |
call init_ring |
mov edx, [device.io_addr] ; init ring destroys edx |
lea eax, [device.private] |
GetRealAddr |
push eax |
and eax, 0xffff |
mov ecx, 1 |
call [device.write_csr] |
pop eax |
shr eax, 16 |
mov ecx, 2 |
call [device.write_csr] |
mov ecx, 4 |
mov eax, 0x0915 |
call [device.write_csr] |
; Set the interrupt mask |
mov ecx, CSR_IMR |
mov eax, IMR |
call [device.write_csr] |
; Initialise the device |
xor ecx, ecx |
mov eax, CSR_INIT |
call [device.write_csr] |
mov esi, 100 |
; xor ecx, ecx |
@@: |
call [device.read_csr] |
test ax, CSR_IDONE |
jnz @f |
dec esi |
jnz @r |
DEBUGF 1,"Initialize timeout!\n" |
@@: |
; Start the device and enable interrupts |
xor ecx, ecx |
mov eax, CSR_START + CSR_INTEN |
call [device.write_csr] |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
; get link status |
mov [device.state], ETH_LINK_UNKOWN |
call check_media |
DEBUGF 1,"reset complete\n" |
xor eax, eax |
ret |
align 4 |
init_ring: |
DEBUGF 1,"init ring\n" |
lea edi, [device.rx_ring] |
mov eax, edi |
GetRealAddr |
mov [device.rx_ring_phys], eax |
mov ecx, RX_RING_SIZE |
.rx_init: |
push ecx |
stdcall KernelAlloc, PKT_BUF_SZ |
pop ecx |
mov [edi + descriptor.virtual], eax |
GetRealAddr |
mov [edi + descriptor.base], eax |
mov [edi + descriptor.length], - PKT_BUF_SZ |
mov [edi + descriptor.status], RXSTAT_OWN |
mov dword [edi + descriptor.msg_length], 0 ; also clears misc field |
add edi, descriptor.size |
dec ecx |
jnz .rx_init |
lea edi, [device.tx_ring] |
mov eax, edi |
GetRealAddr |
mov [device.tx_ring_phys], eax |
mov ecx, TX_RING_SIZE |
.tx_init: |
mov [edi + descriptor.status], 0 |
add edi, descriptor.size |
dec ecx |
jnz .tx_init |
mov [device.tlen_rlen], (TX_RING_LEN_BITS or RX_RING_LEN_BITS) |
mov [device.cur_tx], 0 |
mov [device.last_tx], 0 |
mov [device.cur_rx], 0 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], 1514 |
ja .nospace ; packet is too long |
cmp dword [esp+8], 60 |
jb .nospace ; packet is too short |
; check descriptor |
lea edi, [device.tx_ring] |
movzx eax, [device.cur_tx] |
shl eax, 4 |
add edi, eax |
test [edi + descriptor.status], TXCTL_OWN |
jnz .nospace |
; descriptor is free, use it |
mov eax, [esp+4] |
mov [edi + descriptor.virtual], eax |
GetRealAddr |
mov [edi + descriptor.base], eax |
; set length |
mov eax, [esp+8] |
neg eax |
mov [edi + descriptor.length], ax |
; put to transfer queue |
mov [edi + descriptor.status], TXCTL_OWN + TXCTL_STP + TXCTL_ENP |
; trigger an immediate send |
mov edx, [device.io_addr] |
xor ecx, ecx ; CSR0 |
call [device.read_csr] |
or eax, CSR_TX |
call [device.write_csr] |
; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ... |
inc [device.cur_tx] |
and [device.cur_tx], TX_RING_SIZE - 1 |
DEBUGF 2," - Packet Sent! " |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
.finish: |
DEBUGF 2," - Done!\n" |
xor eax, eax |
ret 8 |
.nospace: |
DEBUGF 1, 'ERROR: no free transmit descriptors\n' |
stdcall KernelFree, [esp+4] |
or eax, -1 |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
mov edx, [device.io_addr] |
push ecx |
xor ecx, ecx ; CSR0 |
call [device.read_csr] ; get IRQ reason |
call [device.write_csr] ; write it back to ACK |
pop ecx |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The int was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1,"Device: %x status: %x\n", ebx, eax:2 |
push ax |
test ax, CSR_RINT |
jz .not_receive |
push ebx |
.rx_loop: |
pop ebx |
movzx eax, [device.cur_rx] |
shl eax, 4 |
lea edi, [device.rx_ring] |
add edi, eax ; edi now points to current rx ring entry |
mov ax, [edi + descriptor.status] |
DEBUGF 1,"RX packet status: %x\n", eax:4 |
test ax, RXSTAT_OWN ; If this bit is set, the controller OWN's the packet, if not, we do |
jnz .not_receive |
test ax, RXSTAT_ENP |
jz .not_receive |
test ax, RXSTAT_STP |
jz .not_receive |
movzx ecx, [edi + descriptor.msg_length] ; get packet length in ecx |
sub ecx, 4 ; |
; Set pointers for ETH_input |
push ebx |
push .rx_loop ; return address |
push ecx ; packet size |
push [edi + descriptor.virtual] ; packet address |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc [device.packets_rx] |
; now allocate a new buffer |
stdcall KernelAlloc, PKT_BUF_SZ ; Allocate a buffer for the next packet |
mov [edi + descriptor.virtual], eax ; set virtual address |
GetRealAddr |
mov [edi + descriptor.base], eax ; and real address |
; mov word [edi + descriptor.length], - PKT_BUF_SZ |
mov [edi + descriptor.status], RXSTAT_OWN ; give it back to PCnet controller |
inc [device.cur_rx] ; set next receive descriptor |
and [device.cur_rx], RX_RING_SIZE - 1 |
jmp Eth_input |
.not_receive: |
pop ax |
test ax, CSR_TINT |
jz .not_transmit |
.tx_loop: |
lea edi, [device.tx_ring] |
movzx eax, [device.last_tx] |
shl eax, 4 |
add edi, eax |
test [edi + descriptor.status], TXCTL_OWN |
jnz .not_transmit |
mov eax, [edi + descriptor.virtual] |
test eax, eax |
jz .not_transmit |
mov [edi + descriptor.virtual], 0 |
DEBUGF 1,"Removing packet %x from memory\n", eax |
stdcall KernelFree, eax |
inc [device.last_tx] |
and [device.last_tx], TX_RING_SIZE - 1 |
jmp .tx_loop |
.not_transmit: |
ret |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Write MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
write_mac: ; in: mac pushed onto stack (as 3 words) |
DEBUGF 1,"Writing MAC: %x-%x-%x-%x-%x-%x",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2 |
mov edx, [device.io_addr] |
add dx, 2 |
xor eax, eax |
mov ecx, CSR_PAR0 |
@@: |
pop ax |
call [device.write_csr] |
DEBUGF 1,"." |
inc ecx |
cmp ecx, CSR_PAR2 |
jb @r |
DEBUGF 1,"\n" |
; Notice this procedure does not ret, but continues to read_mac instead. |
;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Read MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
read_mac: |
DEBUGF 1,"Reading MAC" |
mov edx, [device.io_addr] |
add dx, 6 |
@@: |
dec dx |
dec dx |
in ax, dx |
push ax |
DEBUGF 1,"." |
cmp edx, [device.io_addr] |
ja @r |
DEBUGF 1," %x-%x-%x-%x-%x-%x\n",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2 |
lea edi, [device.mac] |
pop ax |
stosw |
pop ax |
stosw |
pop ax |
stosw |
ret |
align 4 |
switch_to_wio: |
DEBUGF 1,"Switching to 16-bit mode\n" |
mov [device.read_csr], wio_read_csr |
mov [device.write_csr], wio_write_csr |
mov [device.read_bcr], wio_read_bcr |
mov [device.write_bcr], wio_write_bcr |
mov [device.read_rap], wio_read_rap |
mov [device.write_rap], wio_write_rap |
mov [device.sw_reset], wio_reset |
ret |
align 4 |
switch_to_dwio: |
DEBUGF 1,"Switching to 32-bit mode\n" |
mov [device.read_csr], dwio_read_csr |
mov [device.write_csr], dwio_write_csr |
mov [device.read_bcr], dwio_read_bcr |
mov [device.write_bcr], dwio_write_bcr |
mov [device.read_rap], dwio_read_rap |
mov [device.write_rap], dwio_write_rap |
mov [device.sw_reset], dwio_reset |
ret |
; ecx - index |
; return: |
; eax - data |
align 4 |
wio_read_csr: |
add edx, WIO_RAP |
mov ax, cx |
out dx, ax |
add edx, WIO_RDP - WIO_RAP |
in ax, dx |
and eax, 0xffff |
sub edx, WIO_RDP |
ret |
; eax - data |
; ecx - index |
align 4 |
wio_write_csr: |
add edx, WIO_RAP |
xchg eax, ecx |
out dx, ax |
xchg eax, ecx |
add edx, WIO_RDP - WIO_RAP |
out dx, ax |
sub edx, WIO_RDP |
ret |
; ecx - index |
; return: |
; eax - data |
align 4 |
wio_read_bcr: |
add edx, WIO_RAP |
mov ax, cx |
out dx, ax |
add edx, WIO_BDP - WIO_RAP |
in ax, dx |
and eax, 0xffff |
sub edx, WIO_BDP |
ret |
; eax - data |
; ecx - index |
align 4 |
wio_write_bcr: |
add edx, WIO_RAP |
xchg eax, ecx |
out dx, ax |
xchg eax, ecx |
add edx, WIO_BDP - WIO_RAP |
out dx, ax |
sub edx, WIO_BDP |
ret |
align 4 |
wio_read_rap: |
add edx, WIO_RAP |
in ax, dx |
and eax, 0xffff |
sub edx, WIO_RAP |
ret |
; eax - val |
align 4 |
wio_write_rap: |
add edx, WIO_RAP |
out dx, ax |
sub edx, WIO_RAP |
ret |
align 4 |
wio_reset: |
push eax |
add edx, WIO_RESET |
in ax, dx |
pop eax |
sub edx, WIO_RESET |
ret |
; ecx - index |
; return: |
; eax - data |
align 4 |
dwio_read_csr: |
add edx, DWIO_RAP |
mov eax, ecx |
out dx, eax |
add edx, DWIO_RDP - DWIO_RAP |
in eax, dx |
and eax, 0xffff |
sub edx, DWIO_RDP |
ret |
; ecx - index |
; eax - data |
align 4 |
dwio_write_csr: |
add edx, DWIO_RAP |
xchg eax, ecx |
out dx, eax |
add edx, DWIO_RDP - DWIO_RAP |
xchg eax, ecx |
out dx, eax |
sub edx, DWIO_RDP |
ret |
; ecx - index |
; return: |
; eax - data |
align 4 |
dwio_read_bcr: |
add edx, DWIO_RAP |
mov eax, ecx |
out dx, eax |
add edx, DWIO_BDP - DWIO_RAP |
in eax, dx |
and eax, 0xffff |
sub edx, DWIO_BDP |
ret |
; ecx - index |
; eax - data |
align 4 |
dwio_write_bcr: |
add edx, DWIO_RAP |
xchg eax, ecx |
out dx, eax |
add edx, DWIO_BDP - DWIO_RAP |
xchg eax, ecx |
out dx, eax |
sub edx, DWIO_BDP |
ret |
align 4 |
dwio_read_rap: |
add edx, DWIO_RAP |
in eax, dx |
and eax, 0xffff |
sub edx, DWIO_RAP |
ret |
; eax - val |
align 4 |
dwio_write_rap: |
add edx, DWIO_RAP |
out dx, eax |
sub edx, DWIO_RAP |
ret |
align 4 |
dwio_reset: |
push eax |
add edx, DWIO_RESET |
in eax, dx |
pop eax |
sub edx, DWIO_RESET |
ret |
align 4 |
mdio_read: |
and ecx, 0x1f |
mov ax, [device.phy] |
and ax, 0x1f |
shl ax, 5 |
or ax, cx |
mov ecx, BCR_MIIADDR |
call [device.write_bcr] |
mov ecx, BCR_MIIDATA |
call [device.read_bcr] |
ret |
align 4 |
mdio_write: |
push eax |
and ecx, 0x1f |
mov ax, [device.phy] |
and ax, 0x1f |
shl ax, 5 |
or ax, cx |
mov ecx, BCR_MIIADDR |
call [device.write_bcr] |
pop eax |
mov ecx, BCR_MIIDATA |
call [device.write_bcr] |
ret |
align 4 |
check_media: |
DEBUGF 1, "check_media\n" |
test [device.mii], 1 |
jnz mii_link_ok |
mov ecx, BCR_LED0 |
call [device.read_bcr] |
cmp eax, 0xc0 |
DEBUGF 1, "link status=0x%x\n", ax |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'PCnet',0 ; max 16 chars include zero |
device_l2 db "PCnet/PCI 79C970",0 |
device_l4 db "PCnet/PCI II 79C970A",0 |
device_l5 db "PCnet/FAST 79C971",0 |
device_l6 db "PCnet/FAST+ 79C972",0 |
device_l7 db "PCnet/FAST III 79C973",0 |
device_l8 db "PCnet/Home 79C978",0 |
device_l9 db "PCnet/FAST III 79C975",0 |
options_mapping: |
dd PORT_ASEL ; 0 Auto-select |
dd PORT_AUI ; 1 BNC/AUI |
dd PORT_AUI ; 2 AUI/BNC |
dd PORT_ASEL ; 3 not supported |
dd PORT_10BT or PORT_FD ; 4 10baseT-FD |
dd PORT_ASEL ; 5 not supported |
dd PORT_ASEL ; 6 not supported |
dd PORT_ASEL ; 7 not supported |
dd PORT_ASEL ; 8 not supported |
dd PORT_MII ; 9 MII 10baseT |
dd PORT_MII or PORT_FD ; 10 MII 10baseT-FD |
dd PORT_MII ; 11 MII (autosel) |
dd PORT_10BT ; 12 10BaseT |
dd PORT_MII or PORT_100 ; 13 MII 100BaseTx |
dd PORT_MII or PORT_100 or PORT_FD ; 14 MII 100BaseTx-FD |
dd PORT_ASEL ; 15 not supported |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/netdrv.inc |
---|
0,0 → 1,150 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
include 'bus/pci.inc' |
include 'bus/mii.inc' |
; Kernel variables |
PAGESIZE = 4096 |
PG_SW = 0x003 |
PG_NOCACHE = 0x018 |
; network driver types |
NET_TYPE_ETH = 1 |
NET_TYPE_SLIP = 2 |
; link state |
ETH_LINK_DOWN = 0 ; Link is down |
ETH_LINK_UNKOWN = 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 = 10000b ; gigabit |
LAST_IO = 0 |
macro set_io addr { |
if addr = 0 |
mov edx, [device.io_addr] |
else if addr = LAST_IO |
else |
add edx, addr - LAST_IO |
end if |
LAST_IO = addr |
} |
macro allocate_and_clear dest, size, err { |
; We need to allocate at least 8 pages, if we want a continuous memory in ram |
push edx |
if (size < 8*4096) & (size > 4096) |
stdcall KernelAlloc, 8*4096 |
else |
stdcall KernelAlloc, size |
end if |
pop edx |
test eax, eax |
jz err |
mov dest, eax ; Save the address to it into the device struct |
mov edi, eax ; look at last part of code! |
; Release the unused pages (if any) |
if (size < 8*4096) & (size > 4096) |
add eax, (size/4096+1)*4096 |
mov ecx, 8-(size/4096+1) |
push edx |
call ReleasePages |
pop edx |
end if |
; Clear the allocated buffer |
mov ecx, size/4 ; divide by 4 because of DWORD |
xor eax, eax |
rep stosd |
} |
struc IOCTL { |
.handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at edx |
IOCTL IOCTL |
end virtual |
if used null_op |
align 4 |
null_op: |
or eax, -1 |
ret |
end if |
macro GetRealAddr { ; input and output is eax |
push ax |
call GetPgAddr |
and word[esp], PAGESIZE - 1 |
or ax, word[esp] |
inc esp |
inc esp |
} |
macro NET_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 ? ; |
.bytes_tx dq ? ; Statistics, updated by the driver |
.bytes_rx dq ? ; |
.packets_tx dd ? ; |
.packets_rx dd ? ; |
.state dd ? ; link state (0 = no link) |
.hwacc dd ? ; bitmask stating enabled HW accelerations |
.end: |
} |
macro ETH_DEVICE { |
NET_DEVICE |
.mac dp ? |
dw ? ; qword alignment |
} |
macro SLIP_DEVICE { |
NET_DEVICE |
} |
/kernel/branches/net/drivers/3c59x.asm |
---|
0,0 → 1,2942 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; 3Com network driver for KolibriOS ;; |
;; ;; |
;; Ported to KolibriOS net-branch by hidnplayr (28/05/10) ;; |
;; ;; |
;; Thanks to: scrap metal recyclers, whom provide me with ;; |
;; loads of hardware ;; |
;; diamond: who makes me understand KolibriOS ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; 3C59X.INC ;; |
;; ;; |
;; Ethernet driver for Menuet OS ;; |
;; ;; |
;; Driver for 3Com fast etherlink 3c59x and ;; |
;; etherlink XL 3c900 and 3c905 cards ;; |
;; References: ;; |
;; www.3Com.com - data sheets ;; |
;; DP83840A.pdf - ethernet physical layer ;; |
;; 3c59x.c - linux driver ;; |
;; ethernet driver template by Mike Hibbett ;; |
;; ;; |
;; Credits ;; |
;; Mike Hibbett, ;; |
;; who kindly supplied me with a 3Com905C-TX-M card ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; Copyright (c) 2004, Endre Kozma <endre.kozma@axelero.hu> |
;; All rights reserved. |
;; |
;; Redistribution and use in source and binary forms, with or without |
;; modification, are permitted provided that the following conditions are |
;; met: |
;; |
;; 1. Redistributions of source code must retain the above copyright notice, |
;; this list of conditions and the following disclaimer. |
;; |
;; 2. 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. |
;; |
;; 3. The name of the author may not be used to endorse or promote products |
;; derived from this software without specific prior written permission. |
;; |
;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. |
;; |
;; History |
;; ======= |
;; $Log: 3C59X.INC,v $ |
;; Revision 1.3 2004/07/11 12:21:12 kozma |
;; Support of vortex chips (3c59x) added. |
;; Support of 3c920 and 3c982 added. |
;; Corrections. |
;; |
;; Revision 1.2 2004/06/12 19:40:20 kozma |
;; Function e3c59x_set_available_media added in order to set |
;; the default media in case auto detection finds no valid link. |
;; Incorrect mii check removed (3c900 Cyclone works now). |
;; Cleanups. |
;; |
;; Revision 1.1 2004/06/12 18:27:15 kozma |
;; Initial revision |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
FORCE_FD = 0 ; forcing full duplex mode makes sense at some cards and link types |
PROMISCIOUS = 0 ; enables promiscous mode |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
struc DPD { ; Download Packet Descriptor |
.next_ptr dd ? |
.frame_start_hdr dd ? |
.frag_addr dd ? ; for packet data |
.frag_len dd ? ; for packet data |
.realaddr dd ? |
.size = 32 |
} |
virtual at 0 |
dpd DPD |
end virtual |
struc UPD { ; Upload Packet Descriptor |
.next_ptr dd ? |
.pkt_status dd ? |
.frag_addr dd ? |
.frag_len dd ? ; for packet data |
.realaddr dd ? |
.size = 32 |
} |
virtual at 0 |
upd UPD |
end virtual |
; Registers |
REG_POWER_MGMT_CTRL = 0x7c |
REG_UP_LIST_PTR = 0x38 |
REG_UP_PKT_STATUS = 0x30 |
REG_TX_FREE_THRESH = 0x2f |
REG_DN_LIST_PTR = 0x24 |
REG_DMA_CTRL = 0x20 |
REG_TX_STATUS = 0x1b |
REG_RX_STATUS = 0x18 |
REG_TX_DATA = 0x10 |
; Common window registers |
REG_INT_STATUS = 0xe |
REG_COMMAND = 0xe |
; Register window 7 |
REG_MASTER_STATUS = 0xc |
REG_POWER_MGMT_EVENT = 0xc |
REG_MASTER_LEN = 0x6 |
REG_VLAN_ETHER_TYPE = 0x4 |
REG_VLAN_MASK = 0x0 |
REG_MASTER_ADDRESS = 0x0 |
; Register window 6 |
REG_BYTES_XMITTED_OK = 0xc |
REG_BYTES_RCVD_OK = 0xa |
REG_UPPER_FRAMES_OK = 0x9 |
REG_FRAMES_DEFERRED = 0x8 |
REG_FRAMES_RCVD_OK = 0x7 |
REG_FRAMES_XMITTED_OK = 0x6 |
REG_RX_OVERRUNS = 0x5 |
REG_LATE_COLLISIONS = 0x4 |
REG_SINGLE_COLLISIONS = 0x3 |
REG_MULTIPLE_COLLISIONS = 0x2 |
REG_SQE_ERRORS = 0x1 |
REG_CARRIER_LOST = 0x0 |
; Register window 5 |
REG_INDICATION_ENABLE = 0xc |
REG_INTERRUPT_ENABLE = 0xa |
REG_TX_RECLAIM_THRESH = 0x9 |
REG_RX_FILTER = 0x8 |
REG_RX_EARLY_THRESH = 0x6 |
REG_TX_START_THRESH = 0x0 |
; Register window 4 |
REG_UPPER_BYTES_OK = 0xe |
REG_BAD_SSD = 0xc |
REG_MEDIA_STATUS = 0xa |
REG_PHYSICAL_MGMT = 0x8 |
REG_NETWORK_DIAGNOSTIC = 0x6 |
REG_FIFO_DIAGNOSTIC = 0x4 |
REG_VCO_DIAGNOSTIC = 0x2 ; may not supported |
; Bits in register window 4 |
BIT_AUTOSELECT = 24 |
; Register window 3 |
REG_TX_FREE = 0xc |
REG_RX_FREE = 0xa |
REG_MEDIA_OPTIONS = 0x8 |
REG_MAC_CONTROL = 0x6 |
REG_MAX_PKT_SIZE = 0x4 |
REG_INTERNAL_CONFIG = 0x0 |
; Register window 2 |
REG_RESET_OPTIONS = 0xc |
REG_STATION_MASK_HI = 0xa |
REG_STATION_MASK_MID = 0x8 |
REG_STATION_MASK_LO = 0x6 |
REG_STATION_ADDRESS_HI = 0x4 |
REG_STATION_ADDRESS_MID = 0x2 |
REG_STATION_ADDRESS_LO = 0x0 |
; Register window 1 |
REG_TRIGGER_BITS = 0xc |
REG_SOS_BITS = 0xa |
REG_WAKE_ON_TIMER = 0x8 |
REG_SMB_RXBYTES = 0x7 |
REG_SMB_DIAG = 0x5 |
REG_SMB_ARB = 0x4 |
REG_SMB_STATUS = 0x2 |
REG_SMB_ADDRESS = 0x1 |
REG_SMB_FIFO_DATA = 0x0 |
; Register window 0 |
REG_EEPROM_DATA = 0xc |
REG_EEPROM_COMMAND = 0xa |
REG_BIOS_ROM_DATA = 0x8 |
REG_BIOS_ROM_ADDR = 0x4 |
; Physical management bits |
BIT_MGMT_DIR = 2 ; drive with the data written in mgmtData |
BIT_MGMT_DATA = 1 ; MII management data bit |
BIT_MGMT_CLK = 0 ; MII management clock |
; MII commands |
MII_CMD_MASK = (1111b shl 10) |
MII_CMD_READ = (0110b shl 10) |
MII_CMD_WRITE = (0101b shl 10) |
; MII registers |
REG_MII_BMCR = 0 ; basic mode control register |
REG_MII_BMSR = 1 ; basic mode status register |
REG_MII_ANAR = 4 ; auto negotiation advertisement register |
REG_MII_ANLPAR = 5 ; auto negotiation link partner ability register |
REG_MII_ANER = 6 ; auto negotiation expansion register |
; MII bits |
BIT_MII_AUTONEG_COMPLETE = 5 ; auto-negotiation complete |
BIT_MII_PREAMBLE_SUPPRESSION = 6 |
; eeprom bits and commands |
EEPROM_CMD_READ = 0x80 |
EEPROM_BIT_BUSY = 15 |
; eeprom registers |
EEPROM_REG_OEM_NODE_ADDR= 0xa |
EEPROM_REG_CAPABILITIES = 0x10 |
; Commands for command register |
SELECT_REGISTER_WINDOW = (1 shl 11) |
IS_VORTEX = 0x1 |
IS_BOOMERANG = 0x2 |
IS_CYCLONE = 0x4 |
IS_TORNADO = 0x8 |
EEPROM_8BIT = 0x10 |
HAS_PWR_CTRL = 0x20 |
HAS_MII = 0x40 |
HAS_NWAY = 0x80 |
HAS_CB_FNS = 0x100 |
INVERT_MII_PWR = 0x200 |
INVERT_LED_PWR = 0x400 |
MAX_COLLISION_RESET = 0x800 |
EEPROM_OFFSET = 0x1000 |
HAS_HWCKSM = 0x2000 |
EXTRA_PREAMBLE = 0x4000 |
; Status |
IntLatch = 0x0001 |
HostError = 0x0002 |
TxComplete = 0x0004 |
TxAvailable = 0x0008 |
RxComplete = 0x0010 |
RxEarly = 0x0020 |
IntReq = 0x0040 |
StatsFull = 0x0080 |
DMADone = 0x0100 |
DownComplete = 0x0200 |
UpComplete = 0x0400 |
DMAInProgress = 0x0800 ; 1 shl 11 (DMA controller is still busy) |
CmdInProgress = 0x1000 ; 1 shl 12 (EL3_CMD is still busy) |
S_5_INTS = HostError + RxEarly + UpComplete + DownComplete ;+ TxComplete + RxComplete + TxAvailable |
; Commands |
TotalReset = 0 shl 11 |
SelectWindow = 1 shl 11 |
StartCoax = 2 shl 11 |
RxDisable = 3 shl 11 |
RxEnable = 4 shl 11 |
RxReset = 5 shl 11 |
UpStall = 6 shl 11 |
UpUnstall = (6 shl 11)+1 |
DownStall = (6 shl 11)+2 |
DownUnstall = (6 shl 11)+3 |
RxDiscard = 8 shl 11 |
TxEnable = 9 shl 11 |
TxDisable = 10 shl 11 |
TxReset = 11 shl 11 |
FakeIntr = 12 shl 11 |
AckIntr = 13 shl 11 |
SetIntrEnb = 14 shl 11 |
SetStatusEnb = 15 shl 11 |
SetRxFilter = 16 shl 11 |
SetRxThreshold = 17 shl 11 |
SetTxThreshold = 18 shl 11 |
SetTxStart = 19 shl 11 |
StartDMAUp = 20 shl 11 |
StartDMADown = (20 shl 11)+1 |
StatsEnable = 21 shl 11 |
StatsDisable = 22 shl 11 |
StopCoax = 23 shl 11 |
SetFilterBit = 25 shl 11 |
; Rx mode bits |
RxStation = 1 |
RxMulticast = 2 |
RxBroadcast = 4 |
RxProm = 8 |
; RX/TX buffers sizes |
MAX_ETH_PKT_SIZE = 1536 ; max packet size |
NUM_RX_DESC = 4 ; a power of 2 number |
NUM_TX_DESC = 4 ; a power of 2 number |
MAX_ETH_FRAME_SIZE = 1520 ; size of ethernet frame + bytes alignment |
virtual at ebx |
device: |
ETH_DEVICE |
.dpd_buffer rd (dpd.size*NUM_TX_DESC)/4 |
.upd_buffer rd (upd.size*NUM_RX_DESC)/4 |
.curr_upd dd ? |
.prev_dpd dd ? |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
rb 3 ; alignment |
.prev_tx_frame dd ? |
.ver_id db ? |
.full_bus_master db ? |
.has_hwcksm db ? |
.preamble db ? |
.dn_list_ptr_cleared db ? |
.size = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 1,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types of this hardware dont exist |
; check if the device is already listed |
mov ecx, [VORTEX_DEVICES] |
test ecx, ecx |
jz .maybeboomerang |
mov esi, VORTEX_LIST |
mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
.maybeboomerang: |
mov ecx, [BOOMERANG_DEVICES] |
test ecx, ecx |
jz .firstdevice |
mov esi, BOOMERANG_LIST |
mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice2: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice2 |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
mov ecx, [BOOMERANG_DEVICES] |
add ecx, [VORTEX_DEVICES] |
cmp ecx, MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], null_op |
mov [device.unload], null_op |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Ok, the eth_device structure is ready, let's probe the device |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
movzx ecx, [device.ver_id] |
test word [hw_versions+2+ecx*4], IS_VORTEX |
jz .not_vortex |
mov eax, [VORTEX_DEVICES] ; Add the device structure to our device list |
mov [VORTEX_LIST+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [VORTEX_DEVICES] ; |
.register: |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
call start_device |
ret |
.not_vortex: |
mov eax, [BOOMERANG_DEVICES] ; Add the device structure to our device list |
mov [BOOMERANG_LIST+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [BOOMERANG_DEVICES] |
jmp .register |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;*************************************************************************** |
; Function |
; probe |
; Description |
; Searches for an ethernet card, enables it and clears the rx buffer |
; Destroyed registers |
; eax, ebx, ecx, edx, edi, esi |
; |
;*************************************************************************** |
align 4 |
probe: |
DEBUGF 1,"Probing 3com card\n" |
PCI_make_bus_master |
; wake up the card |
call wake_up |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 ; get device/vendor id |
DEBUGF 1,"Vendor id: 0x%x\n", ax |
cmp ax, 0x10B7 |
jne .notfound |
shr eax, 16 |
DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax |
; get chip version |
mov ecx, HW_VERSIONS_SIZE/4-1 |
.loop: |
cmp ax, [hw_versions+ecx*4] |
jz .found |
loop .loop |
.notfound: |
DEBUGF 1,"Device id not found in list!\n" |
or eax, -1 |
ret |
.found: |
mov esi, [hw_str+ecx*4] |
DEBUGF 1,"Hardware type: %s\n", esi |
mov [device.name], esi |
mov [device.ver_id], cl |
test word [hw_versions+2+ecx*4], HAS_HWCKSM |
setnz [device.has_hwcksm] |
; set pci latency for vortex cards |
test word [hw_versions+2+ecx*4], IS_VORTEX |
jz .not_vortex |
mov eax, 11111000b ; 248 = max latency |
stdcall PciWrite32, [device.pci_bus], [device.pci_dev], PCI_REG_LATENCY, eax |
.not_vortex: |
; set RX/TX functions |
mov ax, EEPROM_REG_CAPABILITIES |
call read_eeprom |
test al, 100000b ; full bus master? |
setnz [device.full_bus_master] |
jnz .boomerang_func |
mov [device.transmit], vortex_transmit |
DEBUGF 1,"Device is a vortex type\n" |
DEBUGF 1,"I'm sorry but vortex code hasnt been tested yet\n" |
DEBUGF 1,"Please contact me on hidnplayr@kolibrios.org\n" |
DEBUGF 1,"If you can help me finish it!\n" |
or eax, -1 |
ret |
jmp @f |
.boomerang_func: ; full bus master, so use boomerang functions |
mov [device.transmit], boomerang_transmit |
DEBUGF 1,"Device is a boomerang type\n" |
@@: |
call read_mac_eeprom |
test byte [device.full_bus_master], 0xff |
jz .set_preamble |
; switch to register window 2 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+2 |
out dx, ax |
; activate xcvr by setting some magic bits |
set_io REG_RESET_OPTIONS |
in ax, dx |
and ax, not 0x4010 |
movzx ecx, [device.ver_id] |
test word [ecx*4+hw_versions+2], INVERT_LED_PWR |
jz @f |
or al, 0x10 |
@@: |
test word [ecx*4+hw_versions+2], INVERT_MII_PWR |
jz @f |
or ah, 0x40 |
@@: |
out dx, ax |
.set_preamble: |
; use preamble as default |
mov byte [device.preamble], 1 ; enable preamble |
call global_reset |
;-------------------------- |
; RESET |
align 4 |
reset: |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n",eax:1 |
movzx ecx, [device.ver_id] |
test word [hw_versions+2+ecx*4], IS_VORTEX |
jz .not_vortex |
mov esi, int_vortex |
jmp .reg_int |
.not_vortex: |
mov esi, int_boomerang |
.reg_int: |
stdcall AttachIntHandler, eax, esi, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 0 |
out dx, ax |
mov ax, StopCoax |
out dx, ax ; stop transceiver |
mov ax, SELECT_REGISTER_WINDOW + 4 |
out dx, ax ; disable UTP |
set_io REG_MEDIA_STATUS |
mov ax, 0x0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 0 |
out dx, ax |
set_io REG_FIFO_DIAGNOSTIC |
mov ax, 0 |
out dx, ax ; disable card |
mov ax, 1 |
out dx, ax ; enable card |
call write_mac |
;<<<<<<<<<<<<<< |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 1 |
out dx, ax |
mov ecx, 32 |
set_io 0x0b |
.loop: |
in al, dx |
loop .loop |
; Get rid of stray ints |
set_io REG_COMMAND |
mov ax, AckIntr + 0xff |
out dx, ax |
mov ax, SetStatusEnb + S_5_INTS |
out dx, ax |
mov ax, SetIntrEnb + S_5_INTS |
out dx, ax |
call set_rx_mode |
call set_active_port |
;>>>>>>>>>> |
call create_rx_ring |
call rx_reset |
call tx_reset |
;>>>>>>>>>>>>>>>>>> |
xor eax, eax |
; clear packet/byte counters |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
ret |
align 4 |
start_device: |
DEBUGF 1,"Starting the device\n" |
set_io 0 |
set_io REG_COMMAND |
mov ax, SetTxThreshold + 60 ;2047 ; recommended by the manual :) |
out dx, ax |
call check_tx_status |
set_io 0 |
set_io REG_COMMAND |
; switch to register window 4 |
mov ax, SELECT_REGISTER_WINDOW+4 |
out dx, ax |
; wait for linkDetect |
set_io REG_MEDIA_STATUS |
mov ecx, 20 ; wait for max 2s |
.link_detect_loop: |
mov esi, 100 |
call Sleep ; 100 ms |
in ax, dx |
test ah, 1000b ; linkDetect |
jnz @f |
loop .link_detect_loop |
DEBUGF 1,"Link detect timed-out!\n" |
@@: |
; print link type |
xor eax, eax |
bsr ax, word [device.state] |
jz @f |
sub ax, 4 |
@@: |
mov esi, [link_str+eax*4] |
DEBUGF 1,"Established Link type: %s\n", esi |
; enable interrupts |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 1 |
out dx, ax |
mov ax, AckIntr + 0xff |
out dx, ax |
mov ax, SetStatusEnb + S_5_INTS |
out dx, ax |
mov ax, SetIntrEnb + S_5_INTS |
out dx, ax |
; Start RX/TX |
set_io 0 |
set_io REG_COMMAND |
mov ax, RxEnable |
out dx, ax |
mov ax, TxEnable |
out dx, ax |
set_io REG_COMMAND |
mov ax, SetRxThreshold + 208 |
out dx, ax |
mov ax, SetTxThreshold + 60 ;16 ; recommended by the manual :) |
out dx, ax |
mov ax, SELECT_REGISTER_WINDOW + 1 |
out dx, ax |
ret |
align 4 |
set_rx_mode: |
DEBUGF 1,"Setting RX mode\n" |
set_io 0 |
set_io REG_COMMAND |
if defined PROMISCIOUS |
mov ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast + RxProm |
else if defined ALLMULTI |
mov ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast |
else |
mov ax, SetRxFilter + RxStation + RxBroadcast |
end if |
out dx, ax |
ret |
;*************************************************************************** |
; Function |
; global_reset |
; Description |
; resets the device |
; Parameters: |
; ebp - io_addr |
; Return value: |
; Destroyed registers |
; ax, ecx, edx, esi |
; |
;***************************************************************************1 |
align 4 |
global_reset: |
DEBUGF 1,"Global reset..\n" |
; GlobalReset |
set_io 0 |
set_io REG_COMMAND |
xor eax, eax |
; or al, 0x14 |
out dx, ax |
; wait for GlobalReset to complete |
mov ecx, 64000 |
.loop: |
in ax , dx |
test ah , 10000b ; check CmdInProgress |
loopz .loop |
DEBUGF 1,"Waiting for nic to boot..\n" |
; wait for 2 seconds for NIC to boot |
mov esi, 2000 |
call Sleep ; 2 seconds |
DEBUGF 1,"Ok!\n" |
ret |
;*************************************************************************** |
; Function |
; tx_reset |
; Description |
; resets and enables transmitter engine |
; |
;*************************************************************************** |
align 4 |
tx_reset: |
DEBUGF 1,"tx reset\n" |
; TxReset |
set_io 0 |
set_io REG_COMMAND |
mov ax, TxReset |
out dx, ax |
; Wait for TxReset to complete |
mov ecx, 200000 |
.tx_reset_loop: |
in ax, dx |
test ah, 10000b ; check CmdInProgress |
jz .tx_set_prev |
dec ecx |
jnz .tx_reset_loop |
.tx_set_prev: |
; init last_dpd |
lea eax, [device.dpd_buffer + (NUM_TX_DESC-1)*dpd.size] |
mov [device.prev_dpd], eax |
.tx_enable: |
ret |
;*************************************************************************** |
; Function |
; rx_reset |
; Description |
; resets and enables receiver engine |
; |
;*************************************************************************** |
align 4 |
rx_reset: |
DEBUGF 1,"rx reset\n" |
set_io 0 |
set_io REG_COMMAND |
mov ax, RxReset or 0x4 |
out dx, ax |
; wait for RxReset to complete |
mov ecx, 200000 |
.loop: |
in ax, dx |
test ah, 10000b ; check CmdInProgress |
jz .done |
dec ecx |
jnz .loop |
.done: |
lea eax, [device.upd_buffer] |
mov [device.curr_upd], eax |
GetRealAddr |
set_io 0 |
set_io REG_UP_LIST_PTR |
out dx, eax |
.rx_enable: |
ret |
align 4 |
create_rx_ring: |
; create upd ring |
lea eax, [device.upd_buffer] |
GetRealAddr |
mov edi, eax ; real addr of first descr |
lea esi, [device.upd_buffer] ; ptr to first descr |
lea edx, [device.upd_buffer + (NUM_RX_DESC-1)*upd.size] ; ptr to last descr |
mov ecx, NUM_RX_DESC |
.upd_loop: |
mov [edx + upd.next_ptr], edi |
push ecx edx |
stdcall KernelAlloc, MAX_ETH_FRAME_SIZE |
pop edx ecx |
mov [esi + upd.realaddr], eax |
call GetPgAddr |
mov [esi + upd.frag_addr], eax |
and [esi + upd.pkt_status], 0 |
mov [esi + upd.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31) |
DEBUGF 1,"UPD: lin=%x phys=%x len=%x next ptr=%x\n", [esi+upd.realaddr]:8, [esi+upd.frag_addr]:8, [esi+upd.frag_len]:8, edi |
DEBUGF 1,"UPD: cur=%x prev=%x\n", esi, edx |
mov edx, esi |
add esi, upd.size |
add edi, upd.size |
dec ecx |
jnz .upd_loop |
ret |
;--------------------------------------------------------------------------- |
; Function |
; try_link_detect |
; Description |
; try_link_detect checks if link exists |
; Parameters |
; ebx = device structure |
; Return value |
; al - 0 ; no link detected |
; al - 1 ; link detected |
; Destroyed registers |
; eax, ebx, ecx, edx, edi, esi |
; |
;--------------------------------------------------------------------------- |
align 4 |
try_link_detect: |
DEBUGF 1,"trying to detect link\n" |
; create self-directed packet |
stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet |
test eax, eax |
jz .fail |
pushd 20 ; Packet parameters for device.transmit |
push eax ; |
mov edi, eax |
lea esi, [device.mac] |
movsw |
movsd |
sub esi, 6 |
movsw |
movsd |
mov ax , 0x0608 |
stosw |
; download self-directed packet |
call [device.transmit] |
; switch to register window 4 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+4 |
out dx, ax |
; See if we have received the packet by now.. |
cmp [device.packets_rx], 0 |
jnz .link_detected |
; switch to register window 4 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+4 |
out dx, ax |
; read linkbeatdetect |
set_io REG_MEDIA_STATUS |
in ax, dx |
test ah, 1000b ; test linkBeatDetect |
jnz .link_detected |
xor al, al |
jmp .finish |
.link_detected: |
DEBUGF 1,"link detected!\n" |
setb al |
.finish: |
test al, al |
jz @f |
or byte [device.state+1], 100b |
@@: |
ret |
.fail: |
ret |
;*************************************************************************** |
; Function |
; try_phy |
; Description |
; try_phy checks the auto-negotiation function |
; in the PHY at PHY index. It can also be extended to |
; include link detection for non-IEEE 802.3u |
; auto-negotiation devices, for instance the BCM5000. ; TODO: BCM5000 |
; Parameters |
; ah - PHY index |
; ebx - device stucture |
; Return value |
; al - 0 link is auto-negotiated |
; al - 1 no link is auto-negotiated |
; Destroyed registers |
; eax, ebx, ecx, edx, esi |
; |
;*************************************************************************** |
align 4 |
try_phy: |
DEBUGF 1,"PHY=%u\n", ah |
DEBUGF 1,"Detecting if device is auto-negotiation capable\n" |
mov al, REG_MII_BMCR |
push eax |
call mdio_read ; returns with window #4 |
or ah , 0x80 ; software reset |
mov esi, eax |
mov eax, dword [esp] |
call mdio_write ; returns with window #4 |
; wait for reset to complete |
mov esi, 2000 |
stdcall Sleep ; 2s |
mov eax, [esp] |
call mdio_read ; returns with window #4 |
test ah , 0x80 |
jnz .fail1 |
mov eax, [esp] |
; wait for a while after reset |
mov esi, 20 |
stdcall Sleep ; 20ms |
mov eax, [esp] |
mov al , REG_MII_BMSR |
call mdio_read ; returns with window #4 |
test al , 1 ; extended capability supported? |
jz .fail2 |
; auto-neg capable? |
test al , 1000b |
jz .fail2 ; not auto-negotiation capable |
DEBUGF 1,"Device is auto-negotiation capable\n" |
; auto-neg complete? |
test al , 100000b |
jnz .auto_neg_ok |
DEBUGF 1,"Restarting auto-negotiation\n" |
; restart auto-negotiation |
mov eax, [esp] |
mov al , REG_MII_ANAR |
push eax |
call mdio_read ; returns with window #4 |
or ax , 1111b shl 5; advertise only 10base-T and 100base-TX |
mov esi, eax |
pop eax |
call mdio_write ; returns with window #4 |
mov eax, [esp] |
call mdio_read ; returns with window #4 |
mov esi, eax |
or bh , 10010b ; restart auto-negotiation |
mov eax, [esp] |
call mdio_write ; returns with window #4 |
mov esi, 4000 |
stdcall Sleep ; 4 seconds |
mov eax, [esp] |
mov al , REG_MII_BMSR |
call mdio_read ; returns with window #4 |
test al , 100000b ; auto-neg complete? |
jnz .auto_neg_ok |
jmp .fail3 |
.auto_neg_ok: |
DEBUGF 1,"Auto-negotiation complete\n" |
; compare advertisement and link partner ability registers |
mov eax, [esp] |
mov al , REG_MII_ANAR |
call mdio_read ; returns with window #4 |
xchg eax, [esp] |
mov al , REG_MII_ANLPAR |
call mdio_read ; returns with window #4 |
pop esi |
and eax, esi |
and eax, 1111100000b |
push eax |
mov word[device.state+2], ax |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax , SELECT_REGISTER_WINDOW+3 |
out dx , ax |
; set full-duplex mode |
set_io REG_MAC_CONTROL |
in ax , dx |
and ax , not 0x120 ; clear full duplex and flow control |
pop esi |
test esi, 1010b shl 5; check for full-duplex |
jz .half_duplex |
or ax , 0x120 ; set full duplex and flow control |
.half_duplex: |
DEBUGF 1,"Using half-duplex\n" |
out dx , ax |
mov al , 1 |
ret |
.fail1: |
DEBUGF 1,"reset failed!\n" |
pop eax |
xor al, al |
ret |
.fail2: |
DEBUGF 1,"This device is not auto-negotiation capable!\n" |
pop eax |
xor al, al |
ret |
.fail3: |
DEBUGF 1,"auto-negotiation reset failed!\n" |
pop eax |
xor al, al |
ret |
;*************************************************************************** |
; Function |
; try_mii |
; Description |
; try_MII checks the on-chip auto-negotiation logic |
; or an off-chip MII PHY, depending upon what is set in |
; xcvrSelect by the caller. |
; It exits when it finds the first device with a good link. |
; Parameters |
; ebp - io_addr |
; Return value |
; al - 0 |
; al - 1 |
; Destroyed registers |
; eax, ebx, ecx, edx, esi |
; |
;*************************************************************************** |
align 4 |
try_mii: |
DEBUGF 1,"trying to find MII PHY\n" |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, (1111b shl 20) |
cmp eax, (1000b shl 20) ; is auto-negotiation set? |
jne .mii_device |
DEBUGF 1,"auto-negotiation is set\n" |
; switch to register window 4 |
set_io REG_COMMAND |
mov ax , SELECT_REGISTER_WINDOW+4 |
out dx , ax |
; PHY==24 is the on-chip auto-negotiation logic |
; it supports only 10base-T and 100base-TX |
mov ah , 24 |
call try_phy |
test al , al |
jz .fail_finish |
mov cl , 24 |
jmp .check_preamble |
.mii_device: |
cmp eax, (0110b shl 20) |
jne .fail_finish |
set_io 0 |
set_io REG_COMMAND |
mov ax , SELECT_REGISTER_WINDOW+4 |
out dx , ax |
set_io REG_PHYSICAL_MGMT |
in ax , dx |
and al , (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_DATA) |
cmp al , (1 shl BIT_MGMT_DATA) |
je .search_for_phy |
xor al , al |
ret |
.search_for_phy: |
; search for PHY |
mov cx , 31 |
.search_phy_loop: |
DEBUGF 1,"Searching the PHY\n" |
cmp cx , 24 |
je .next_phy |
mov ah , cl ; ah = phy |
mov al , REG_MII_BMCR ; al = Basic Mode Status Register |
push cx |
call mdio_read |
pop cx |
test ax , ax |
jz .next_phy |
cmp ax , 0xffff |
je .next_phy |
mov ah , cl ; ah = phy |
push cx |
call try_phy |
pop cx |
test al , al |
jnz .check_preamble |
.next_phy: |
loopw .search_phy_loop |
.fail_finish: |
xor al, al |
ret |
; epilog |
.check_preamble: |
DEBUGF 1,"Using PHY: %u\nChecking PreAmble\n", cl |
push eax ; eax contains the return value of try_phy |
; check hard coded preamble forcing |
movzx eax, [device.ver_id] |
test word [eax*4+hw_versions+2], EXTRA_PREAMBLE |
setnz [device.preamble] ; force preamble |
jnz .finish |
; check mii for preamble suppression |
mov ah, cl |
mov al, REG_MII_BMSR |
call mdio_read |
test al, 1000000b ; preamble suppression? |
setz [device.preamble] ; no |
.finish: |
pop eax |
ret |
;*************************************************************************** |
; Function |
; test_packet |
; Description |
; try_loopback try a loopback packet for 10BASE2 or AUI port |
; Parameters |
; ebx = device structure |
; |
;*************************************************************************** |
align 4 |
test_packet: |
DEBUGF 1,"sending test packet\n" |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
; set fullDuplexEnable in MacControl register |
set_io REG_MAC_CONTROL |
in ax, dx |
or ax, 0x120 |
out dx, ax |
; switch to register window 5 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+5 |
out dx, ax |
; set RxFilter to enable individual address matches |
mov ax, (10000b shl 11) |
set_io REG_RX_FILTER |
in al, dx |
or al, 1 |
set_io REG_COMMAND |
out dx, ax |
; issue RxEnable and TxEnable |
call rx_reset |
call tx_reset |
; create self-directed packet |
stdcall KernelAlloc, 20 ; create a buffer for the self-directed packet |
test eax, eax |
jz .fail |
pushd 20 ; Packet parameters for device.transmit |
push eax ; |
mov edi, eax |
lea esi, [device.mac] |
movsw |
movsd |
sub esi, 6 |
movsw |
movsd |
mov ax , 0x0608 |
stosw |
; download self-directed packet |
call [device.transmit] |
; wait for 2s |
mov esi, 2000 |
call Sleep |
; check if self-directed packet is received |
mov eax, [device.packets_rx] |
test eax, eax |
jnz .finish |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
; clear fullDuplexEnable in MacControl register |
set_io REG_MAC_CONTROL |
in ax , dx |
and ax , not 0x120 |
out dx , ax |
.fail: |
xor eax, eax |
.finish: |
ret |
;*************************************************************************** |
; Function |
; try_loopback |
; Description |
; tries a loopback packet for 10BASE2 or AUI port |
; Parameters |
; al - 0: 10Mbps AUI connector |
; 1: 10BASE-2 |
; ebp - io_addr |
; Return value |
; al - 0 |
; al - 1 |
; Destroyed registers |
; eax, ebx, ecx, edx, edi, esi |
; |
;*************************************************************************** |
align 4 |
try_loopback: |
DEBUGF 1,"trying loopback\n" |
push eax |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
mov eax, [esp] |
mov cl, al |
inc cl |
shl cl, 3 |
or byte [device.state+1], cl |
test al, al ; aui or coax? |
jz .complete_loopback |
; enable 100BASE-2 DC-DC converter |
mov ax, (10b shl 11) ; EnableDcConverter |
out dx, ax |
.complete_loopback: |
mov cx, 2 ; give a port 3 chances to complete a loopback |
.next_try: |
push ecx |
call test_packet |
pop ecx |
test eax, eax |
loopzw .next_try |
.finish: |
xchg eax, [esp] |
test al, al |
jz .aui_finish |
; issue DisableDcConverter command |
set_io 0 |
set_io REG_COMMAND |
mov ax, (10111b shl 11) |
out dx, ax |
.aui_finish: |
pop eax ; al contains the result of operation |
test al, al |
jnz @f |
and byte [device.state+1], not 11000b |
@@: |
ret |
;*************************************************************************** |
; Function |
; set_active_port |
; Description |
; It selects the media port (transceiver) to be used |
; Return value: |
; Destroyed registers |
; eax, ebx, ecx, edx, edi, esi |
; |
;*************************************************************************** |
align 4 |
set_active_port: |
DEBUGF 1,"Trying to find the active port\n" |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW + 3 |
out dx, ax |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
test eax, (1 shl 24) ; check if autoselect enable |
jz .set_first_available_media |
; check 100BASE-TX and 10BASE-T |
set_io REG_MEDIA_OPTIONS |
in ax, dx |
test al, 1010b ; check whether 100BASE-TX or 10BASE-T available |
jz .mii_device ; they are not available |
; set auto-negotiation |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
or eax, (1000b shl 20) |
out dx, eax |
call try_mii |
test al, al |
jz .mii_device |
DEBUGF 1,"Using auto negotiation\n" |
ret |
.mii_device: |
; switch to register window 3 |
set_io 0 |
; check for off-chip mii device |
set_io REG_MEDIA_OPTIONS |
in ax, dx |
test al, 1000000b ; check miiDevice |
jz .base_fx |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
or eax, (0110b shl 20) ; set MIIDevice |
out dx, eax |
call try_mii |
test al, al |
jz .base_fx |
DEBUGF 1,"Using off-chip mii device\n" |
ret |
.base_fx: |
; switch to register window 3 |
set_io 0 |
; check for 100BASE-FX |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
test al, 100b ; check 100BASE-FX |
jz .aui_enable |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
or eax, (0101b shl 20) ; set 100base-FX |
out dx, eax |
call try_link_detect |
test al, al |
jz .aui_enable |
DEBUGF 1,"Using 100Base-FX\n" |
ret |
.aui_enable: |
; switch to register window 3 |
set_io 0 |
; check for 10Mbps AUI connector |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
test al, 100000b ; check 10Mbps AUI connector |
jz .coax_available |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
or eax, (0001b shl 20) ; set 10Mbps AUI connector |
out dx, eax |
xor al, al ; try 10Mbps AUI connector |
call try_loopback |
test al, al |
jz .coax_available |
DEBUGF 1,"Using 10Mbps aui\n" |
ret |
.coax_available: |
; switch to register window 3 |
set_io 0 |
; check for coaxial 10BASE-2 port |
set_io REG_MEDIA_OPTIONS |
in ax, dx ; read media option register |
test al, 10000b ; check 10BASE-2 |
jz .set_first_available_media |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) |
or eax, (0011b shl 20) ; set 10BASE-2 |
out dx, eax |
mov al, 1 |
call try_loopback |
test al, al |
jz .set_first_available_media |
DEBUGF 1,"Using 10BASE-2 port\n" |
ret |
.set_first_available_media: |
DEBUGF 1,"Using the first available media\n" |
;*************************************************************************** |
; Function |
; set_available_media |
; Description |
; sets the first available media |
; Parameters |
; ebx - ptr to device struct |
; Return value |
; al - 0 |
; al - 1 |
; Destroyed registers |
; eax, edx |
; |
;*************************************************************************** |
align 4 |
set_available_media: |
DEBUGF 1,"Setting the available media\n" |
; switch to register window 3 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+3 |
out dx, ax |
set_io REG_MEDIA_OPTIONS |
in ax, dx |
DEBUGF 1,"available media:%x\n", al |
mov cl, al |
set_io REG_INTERNAL_CONFIG |
in eax, dx |
and eax, not (1111b shl 20) ; these bits hold the 'transceiver select' value |
test cl, 10b ; baseTXAvailable |
jz @f |
DEBUGF 1,"base TX is available\n" |
or eax, (100b shl 20) |
if defined FORCE_FD |
mov word [device.state], (1 shl 8) |
else |
mov word [device.mode], (1 shl 7) |
end if |
jmp .set_media |
@@: |
test cl, 100b ; baseFXAvailable |
jz @f |
DEBUGF 1,"base FX is available\n" |
or eax, (101b shl 20) |
mov word [device.state], (1 shl 10) |
jmp .set_media |
@@: |
test cl, 1000000b ; miiDevice |
jz @f |
DEBUGF 1,"mii-device is available\n" |
or eax, (0110b shl 20) |
mov word [device.state], (1 shl 13) |
jmp .set_media |
@@: |
test cl, 1000b ; 10bTAvailable |
jz @f |
DEBUGF 1,"10base-T is available\n" |
.set_default: |
if FORCE_FD |
mov word [device.state], (1 shl 6) |
else |
mov word [device.state], (1 shl 5) |
end if |
jmp .set_media |
@@: |
test cl, 10000b ; coaxAvailable |
jz @f |
DEBUGF 1,"coax is available\n" |
push eax |
set_io REG_COMMAND |
mov ax, (10b shl 11) ; EnableDcConverter |
out dx, ax |
pop eax |
or eax, (11b shl 20) |
mov word [device.state], (1 shl 12) |
jmp .set_media |
@@: |
test cl, 10000b ; auiAvailable |
jz .set_default |
DEBUGF 1,"AUI is available\n" |
or eax, (1 shl 20) |
mov word [device.state], (1 shl 11) |
.set_media: |
set_io 0 |
set_io REG_INTERNAL_CONFIG |
out dx, eax |
if FORCE_FD |
DEBUGF 1,"Forcing full duplex\n" |
set_io REG_MAC_CONTROL |
in ax, dx |
or ax, 0x120 |
out dx, ax |
end if |
mov al, 1 |
ret |
;*************************************************************************** |
; Function |
; wake_up |
; Description |
; set the power state to D0 |
; |
;*************************************************************************** |
align 4 |
wake_up: |
DEBUGF 1,"Waking up NIC: " |
; wake up - we directly do it by programming PCI |
; check if the device is power management capable |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_REG_STATUS |
test al, 10000b ; is there "new capabilities" linked list? |
jz .device_awake |
; search for power management register |
stdcall PciRead16, [device.pci_bus], [device.pci_dev], PCI_REG_CAP_PTR |
cmp al, 0x3f |
jbe .device_awake |
; traverse the list |
movzx esi, al |
.pm_loop: |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi |
cmp al , 1 |
je .set_pm_state |
movzx esi, ah |
test ah , ah |
jnz .pm_loop |
jmp .device_awake |
; waku up the device if necessary |
.set_pm_state: |
add esi, PCI_REG_PM_CTRL |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], esi |
test al, 3 |
jz .device_awake |
and al, not 11b ; set state to D0 |
stdcall PciWrite32, [device.pci_bus], [device.pci_dev], esi, eax |
.device_awake: |
DEBUGF 1,"Device is awake\n" |
ret |
;*************************************************************************** |
; Function |
; write_eeprom |
; Description |
; reads eeprom |
; Note : the caller must switch to the register window 0 |
; before calling this function |
; Parameters: |
; ax - register to be read (only the first 63 words can be read) |
; cx - value to be read into the register |
; Return value: |
; ax - word read |
; Destroyed registers |
; ax, ebx, edx |
; |
;*************************************************************************** |
; align 4 |
;write_eeprom: |
; mov edx, [io_addr] |
; add edx, REG_EEPROM_COMMAND |
; cmp ah, 11b |
; ja .finish ; address may have a value of maximal 1023 |
; shl ax, 2 |
; shr al, 2 |
; push eax |
;; wait for busy |
; mov ebx, 0xffff |
;@@: |
; in ax, dx |
; test ah, 0x80 |
; jz .write_enable |
; dec ebx |
; jns @r |
;; write enable |
;.write_enable: |
; xor eax, eax |
; mov eax, (11b shl 4) |
; out dx, ax |
;; wait for busy |
; mov ebx, 0xffff |
;@@: |
; in ax, dx |
; test ah, 0x80 |
; jz .erase_loop |
; dec ebx |
; jns @r |
;.erase_loop: |
; pop eax |
; push eax |
; or ax, (11b shl 6) ; erase register |
; out dx, ax |
; mov ebx, 0xffff |
;@@: |
; in ax, dx |
; test ah, 0x80 |
; jz .write_reg |
; dec ebx |
; jns @r |
;.write_reg: |
; add edx, REG_EEPROM_DATA-REG_EEPROM_COMMAND |
; mov eax, ecx |
; out dx, ax |
;; write enable |
; add edx, REG_EEPROM_COMMAND-REG_EEPROM_DATA |
; xor eax, eax |
; mov eax, (11b shl 4) |
; out dx, ax |
; wait for busy |
; mov ebx, 0xffff |
;@@: |
; in ax, dx |
; test ah, 0x80 |
; jz .issue_write_reg |
; dec ebx |
; jns @r |
;.issue_write_reg: |
; pop eax |
; or ax, 01b shl 6 |
; out dx, ax |
;.finish: |
; ret |
;*************************************************************************** |
; Function |
; read_eeprom |
; Description |
; reads eeprom |
; Parameters: |
; ax - register to be read (only the first 63 words can be read) |
; ebx = driver structure |
; Return value: |
; ax - word read |
; Destroyed registers |
; ax, ebx, edx |
; |
;*************************************************************************** |
align 4 |
read_eeprom: |
DEBUGF 1,"Reading from eeprom.. " |
push eax |
; switch to register window 0 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+0 |
out dx, ax |
pop eax |
and ax, 111111b ; take only the first 6 bits into account |
movzx esi, [device.ver_id] |
test word [esi*4+hw_versions+2], EEPROM_8BIT |
jz @f |
add ax, 0x230 ; hardware constant |
jmp .read |
@@: |
add ax, EEPROM_CMD_READ |
test word [esi*4+hw_versions+2], EEPROM_OFFSET |
jz .read |
add ax, 0x30 |
.read: |
set_io REG_EEPROM_COMMAND |
out dx, ax |
mov ecx, 0xffff ; duration of about 162 us ;-) |
.wait_for_reading: |
in ax, dx |
test ah, 0x80 ; check bit eepromBusy |
jz .read_data |
loop .wait_for_reading |
.read_data: |
set_io REG_EEPROM_DATA |
in ax, dx |
DEBUGF 1,"ok!\n" |
ret |
;*************************************************************************** |
; Function |
; mdio_sync |
; Description |
; initial synchronization |
; Parameters |
; ebp - io_addr |
; Return value |
; Destroyed registers |
; ax, edx, cl |
; |
;*************************************************************************** |
align 4 |
mdio_sync: |
DEBUGF 1,"syncing mdio\n" |
; switch to register window 4 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+4 |
out dx, ax |
cmp [device.preamble], 0 |
je .no_preamble |
; send 32 logic ones |
set_io REG_PHYSICAL_MGMT |
mov ecx, 31 |
.loop: |
mov ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR) |
out dx, ax |
in ax, dx ; delay |
mov ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_CLK) |
out dx, ax |
in ax, dx ; delay |
loop .loop |
.no_preamble: |
ret |
;*************************************************************************** |
; Function |
; mdio_read |
; Description |
; read MII register |
; see page 16 in D83840A.pdf |
; Parameters |
; ah - PHY addr |
; al - register addr |
; ebx = device structure |
; Return value |
; ax - register read |
; |
;*************************************************************************** |
align 4 |
mdio_read: |
DEBUGF 1,"Reading MII registers\n" |
push eax |
call mdio_sync ; returns with window #4 |
pop eax |
set_io 0 |
set_io REG_PHYSICAL_MGMT |
shl al, 3 |
shr ax, 3 |
and ax, not MII_CMD_MASK |
or ax, MII_CMD_READ |
mov esi, eax |
mov ecx, 13 |
.cmd_loop: |
mov ax, (1 shl BIT_MGMT_DIR) ; write mii |
bt esi, ecx |
jnc .zero_bit |
or al, (1 shl BIT_MGMT_DATA) |
.zero_bit: |
out dx, ax |
push ax |
in ax, dx ; delay |
pop ax |
or al, (1 shl BIT_MGMT_CLK) ; write |
out dx, ax |
in ax, dx ; delay |
loop .cmd_loop |
; read data (18 bits with the two transition bits) |
mov ecx, 17 |
xor esi, esi |
.read_loop: |
shl esi, 1 |
xor eax, eax ; read comand |
out dx, ax |
in ax, dx ; delay |
in ax, dx |
test al, (1 shl BIT_MGMT_DATA) |
jz .dont_set |
inc esi |
.dont_set: |
mov ax, (1 shl BIT_MGMT_CLK) |
out dx, ax |
in ax, dx ; delay |
loop .read_loop |
mov eax, esi |
ret |
;*************************************************************************** |
; Function |
; mdio_write |
; Description |
; write MII register |
; see page 16 in D83840A.pdf |
; Parameters |
; ah - PHY addr |
; al - register addr |
; si - word to be written |
; Return value |
; ax - register read |
; |
;*************************************************************************** |
align 4 |
mdio_write: |
DEBUGF 1,"Writing MII registers\n" |
push eax |
call mdio_sync |
pop eax |
set_io 0 |
set_io REG_PHYSICAL_MGMT |
shl al, 3 |
shr ax, 3 |
and ax, not MII_CMD_MASK |
or ax, MII_CMD_WRITE |
shl eax, 2 |
or eax, 10b ; transition bits |
shl eax, 16 |
mov ax, si |
mov esi, eax |
mov ecx, 31 |
.cmd_loop: |
mov ax, (1 shl BIT_MGMT_DIR) ; write mii |
bt esi, ecx |
jnc @f |
or al, (1 shl BIT_MGMT_DATA) |
@@: |
out dx, ax |
push eax |
in ax, dx ; delay |
pop eax |
or al, (1 shl BIT_MGMT_CLK) ; write |
out dx, ax |
in ax, dx ; delay |
loop .cmd_loop |
ret |
;*************************************************************************** |
; Function |
; check_tx_status |
; Description |
; Checks TxStatus queue. |
; Return value |
; al - 0 no error was found |
; al - 1 error was found TxReset was needed |
; Destroyed registers |
; eax, ecx, edx, ebp |
; |
;*************************************************************************** |
align 4 |
check_tx_status: |
DEBUGF 1,"Checking TX status\n" |
; clear TxStatus queue |
set_io 0 |
set_io REG_TX_STATUS |
mov ecx, 31 ; max number of queue entries |
.tx_status_loop: |
in al, dx |
test al, al |
jz .finish ; no error |
test al, 0x3f |
jnz .error |
.no_error_found: |
; clear current TxStatus entry which advances the next one |
xor al, al |
out dx, al |
loop .tx_status_loop |
.finish: |
ret |
.error: |
call tx_reset |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit (vortex) ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
vortex_transmit: |
DEBUGF 1,"Sending packet (vortex)\n" |
cmp dword [esp+8], MAX_ETH_FRAME_SIZE |
ja .finish ; packet is too long |
call check_tx_status |
; switch to register window 7 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+7 |
out dx, ax |
; check for master operation in progress |
set_io REG_MASTER_STATUS |
in ax, dx |
test ah, 0x80 |
jnz .finish ; no DMA for sending |
; program frame address to be sent |
set_io REG_MASTER_ADDRESS |
mov eax, [esp+4] |
call GetPgAddr |
out dx, eax |
; program frame length |
set_io REG_MASTER_LEN |
mov eax, [esp+8] |
;;; and eax, not 3 |
out dx, ax |
; start DMA Down |
set_io REG_COMMAND |
mov ax, (10100b shl 11) + 1 ; StartDMADown |
out dx, ax |
.finish: |
call KernelFree |
add esp, 4 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit (boomerang) ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
boomerang_transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], MAX_ETH_FRAME_SIZE |
ja .fail |
call check_tx_status |
; calculate descriptor address |
mov esi, [device.prev_dpd] |
DEBUGF 1,"Previous DPD: %x\n", esi |
add esi, dpd.size |
lea ecx, [device.dpd_buffer + (NUM_TX_DESC)*dpd.size] |
cmp esi, ecx |
jb @f |
lea esi, [device.dpd_buffer] ; Wrap if needed |
@@: |
DEBUGF 1,"Found a free DPD: %x\n", esi |
; check DnListPtr |
set_io 0 |
set_io REG_DN_LIST_PTR |
in eax, dx |
; mark if Dn_List_Ptr is cleared |
test eax, eax |
setz [device.dn_list_ptr_cleared] |
; finish if no more free descriptor is available - FIXME! |
; cmp eax, esi |
; jz .finish |
; update statistics |
inc [device.packets_tx] |
mov ecx, [esp+8] ; buffer size |
add dword [device.bytes_tx], ecx |
adc dword [device.bytes_tx + 4], 0 |
; program DPD |
and [esi+dpd.next_ptr], 0 |
mov eax, [esp+4] ; Tx buffer address |
mov [esi+dpd.realaddr], eax |
call GetPgAddr |
mov [esi+dpd.frag_addr], eax |
mov ecx, [esp+8] ; packet size |
or ecx, 0x80000000 ; last fragment |
mov [esi+dpd.frag_len], ecx |
mov ecx, [esp+8] ; packet size |
; or ecx, 0x8000 ; transmission complete notification |
or ecx, 1 shl 31 |
; test byte [device.has_hwcksm], 0xff |
; jz @f |
; or ecx, (1 shl 26) ; set AddTcpChecksum |
;@@: |
mov [esi+dpd.frame_start_hdr], ecx |
DEBUGF 1,"DPD: lin=%x phys=%x len=%x start hdr=%x\n", [esi+dpd.realaddr]:8, [esi+dpd.frag_addr]:8, [esi+dpd.frag_len]:8, [esi+dpd.frame_start_hdr]:8 |
; calculate physical address of dpd |
mov eax, esi |
GetRealAddr |
cmp [device.dn_list_ptr_cleared], 0 |
jz .add_to_list |
; write Dn_List_Ptr |
DEBUGF 1,"DPD phys addr=%x\n", eax |
set_io 0 |
set_io REG_DN_LIST_PTR |
out dx, eax |
jmp .finish |
.add_to_list: |
DEBUGF 1,"Adding To list\n" |
push eax |
; DnStall |
set_io 0 |
set_io REG_COMMAND |
mov ax, ((110b shl 11)+2) |
out dx, ax |
; wait for DnStall to complete |
DEBUGF 1,"Waiting for DnStall\n" |
mov ecx, 6000 |
.wait_for_stall: |
in ax, dx ; read REG_INT_STATUS |
test ah, 10000b |
jz .dnstall_ok |
dec ecx |
jnz .wait_for_stall |
.dnstall_ok: |
DEBUGF 1,"DnStall ok!\n" |
mov ecx, [device.prev_dpd] |
mov [ecx+dpd.next_ptr], eax |
set_io 0 |
set_io REG_DN_LIST_PTR |
in eax, dx |
test eax, eax |
pop eax |
jnz .dnunstall |
; if Dn_List_Ptr has been cleared fill it up |
DEBUGF 1,"DnList Ptr has been cleared\n" |
out dx, eax |
.dnunstall: |
; DnUnStall |
set_io 0 |
set_io REG_COMMAND |
mov ax, ((110b shl 11)+3) |
out dx, ax |
.finish: |
mov [device.prev_dpd], esi |
xor eax, eax |
ret 8 |
.fail: |
stdcall KernelFree, [esp+4] |
or eax, -1 |
ret 8 |
;--------------------------------- |
; Write MAC |
align 4 |
write_mac: |
DEBUGF 1,"Writing mac\n" |
set_io 0 |
set_io REG_COMMAND |
; switch to register window 2 |
mov ax, SELECT_REGISTER_WINDOW+2 |
out dx, ax |
; write MAC addres back into the station address registers |
set_io REG_STATION_ADDRESS_LO |
lea esi, [device.mac] |
outsw |
inc dx |
inc dx |
outsw |
inc dx |
inc dx |
outsw |
;---------------------------- |
; Read MAC |
align 4 |
read_mac: |
set_io 0 |
set_io REG_COMMAND |
; switch to register window 2 |
mov ax, SELECT_REGISTER_WINDOW+2 |
out dx, ax |
; write MAC addres back into the station address registers |
set_io REG_STATION_ADDRESS_LO |
lea edi, [device.mac] |
insw |
inc dx |
inc dx |
insw |
inc dx |
inc dx |
insw |
DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;------------------------------------ |
; Read MAC from eeprom |
align 4 |
read_mac_eeprom: ; Tested - ok |
DEBUGF 1,"Reading mac from eeprom\n" |
; read MAC from eeprom |
mov ecx, 3 |
.mac_loop: |
lea ax, [EEPROM_REG_OEM_NODE_ADDR+ecx-1] |
push ecx |
call read_eeprom |
pop ecx |
xchg ah, al ; htons |
mov word [device.mac+ecx*2-2], ax |
loop .mac_loop |
DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Vortex Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_vortex: |
DEBUGF 1,"vortex IRQ %x ",eax:2 |
; find pointer of device wich made IRQ occur |
mov esi, VORTEX_LIST |
mov ecx, [VORTEX_DEVICES] |
test ecx, ecx |
jz .fail |
.nextdevice: |
mov ebx, dword [esi] |
set_io 0 |
set_io REG_INT_STATUS |
in ax, dx |
;; and ax, INT_MASK |
jnz .got_it |
add esi, 4 |
test ax , ax |
jnz .got_it |
loop .nextdevice |
.fail: |
ret |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ",ebx,eax:4 |
test ax, RxComplete |
jz .noRX |
set_io 0 |
.rx_status_loop: |
; examine RxStatus |
set_io REG_RX_STATUS |
in ax, dx |
test ax, ax |
jz .finish |
test ah, 0x80 ; rxIncomplete |
jnz .finish |
test ah, 0x40 |
jz .check_length |
; discard the top frame received advancing the next one |
set_io REG_COMMAND |
mov ax, (01000b shl 11) |
out dx, ax |
jmp .rx_status_loop |
.check_length: |
and eax, 0x1fff |
cmp eax, MAX_ETH_PKT_SIZE |
ja .discard_frame ; frame is too long discard it |
.check_dma: |
mov ecx, eax |
; switch to register window 7 |
set_io 0 |
set_io REG_COMMAND |
mov ax, SELECT_REGISTER_WINDOW+7 |
out dx, ax |
; check for master operation in progress |
set_io REG_MASTER_STATUS |
in ax, dx |
test ah, 0x80 |
jnz .finish |
.read_frame: |
; program buffer address to read in |
push ecx |
stdcall KernelAlloc, MAX_ETH_FRAME_SIZE |
pop ecx |
test eax, eax |
jz .finish |
push .discard_frame |
push ecx |
push eax |
; zero_to_dma eax |
set_io REG_MASTER_ADDRESS |
out dx, eax |
; program frame length |
set_io REG_MASTER_LEN |
mov ax, 1560 |
out dx, ax |
; start DMA Up |
set_io REG_COMMAND |
mov ax, (10100b shl 11) ; StartDMAUp |
out dx, ax |
; check for master operation in progress |
set_io REG_MASTER_STATUS ; TODO: use timeout and reset after timeout expired |
.dma_loop: |
in ax, dx |
test ah, 0x80 |
jnz .dma_loop |
; registrate the received packet to kernel |
jmp Eth_input |
; discard the top frame received |
.discard_frame: |
set_io 0 |
set_io REG_COMMAND |
mov ax, (01000b shl 11) |
out dx, ax |
.finish: |
.noRX: |
test ax, DMADone |
jz .noDMA |
push ax |
set_io 0 |
set_io 12 |
in ax, dx |
test ax, 0x1000 |
jz .nodmaclear |
mov ax, 0x1000 |
out dx, ax |
.nodmaclear: |
pop ax |
DEBUGF 1, "DMA Done!\n", cx |
.noDMA: |
.ACK: |
set_io 0 |
set_io REG_COMMAND |
mov ax, AckIntr + IntReq + IntLatch |
out dx, ax |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Boomerang Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_boomerang: |
DEBUGF 1,"\nBoomerang int\n" |
; find pointer of device wich made IRQ occur |
mov ecx, [BOOMERANG_DEVICES] |
test ecx, ecx |
jz .nothing |
mov esi, BOOMERANG_LIST |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io REG_INT_STATUS |
in ax, dx |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, ax |
push ax |
; disable all INTS |
set_io REG_COMMAND |
mov ax, SetIntrEnb |
out dx, ax |
;-------------------------------------------------------------------------- |
test word[esp], UpComplete |
jz .noRX |
push ebx |
.receive: |
DEBUGF 1,"UpComplete\n" |
; check if packet is uploaded |
mov esi, [device.curr_upd] |
test byte [esi+upd.pkt_status+1], 0x80 ; upPktComplete |
jz .finish |
DEBUGF 1, "Current upd: %x\n", esi |
; packet is uploaded check for any error |
.check_error: |
test byte [esi+upd.pkt_status+1], 0x40 ; upError |
jz .copy_packet_length |
DEBUGF 1,"Error in packet\n" |
and [esi+upd.pkt_status], 0 ; mark packet as read |
jmp .finish |
.copy_packet_length: |
mov ecx, [esi+upd.pkt_status] |
and ecx, 0x1fff |
; cmp ecx, MAX_ETH_PKT_SIZE |
; jbe .copy_packet |
; and [esi+upd.pkt_status], 0 |
; jmp .finish |
; .copy_packet: |
DEBUGF 1, "Received %u bytes in buffer %x\n", ecx, [esi+upd.realaddr]:8 |
push dword .loop ;.finish |
push ecx |
push [esi+upd.realaddr] |
; update statistics |
inc [device.packets_rx] |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
; update UPD (Alloc new buffer for next packet) |
stdcall KernelAlloc, MAX_ETH_FRAME_SIZE |
mov [esi + upd.realaddr], eax |
GetRealAddr |
mov [esi + upd.frag_addr], eax |
and [esi + upd.pkt_status], 0 |
mov [esi + upd.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31) |
; Update UPD pointer |
add esi, upd.size |
lea ecx, [device.upd_buffer+(NUM_RX_DESC)*upd.size] |
cmp esi, ecx |
jb @f |
lea esi, [device.upd_buffer] |
@@: |
mov [device.curr_upd], esi |
DEBUGF 1, "Next upd: %x\n", esi |
jmp Eth_input |
.loop: |
mov ebx, [esp] |
jmp .receive |
.finish: |
pop ebx |
; check if the NIC is in the upStall state |
set_io 0 |
set_io REG_UP_PKT_STATUS |
in eax, dx |
test ah, 0x20 ; UpStalled |
jz .noUpUnStall |
DEBUGF 1, "upUnStalling\n" |
; issue upUnStall command |
set_io REG_COMMAND |
mov ax, ((11b shl 12)+1) ; upUnStall |
out dx, ax |
;;;; FIXME: make upunstall work |
.noUpUnStall: |
.noRX: |
test word[esp], DownComplete |
jz .noTX |
DEBUGF 1, "Downcomplete!\n" |
mov ecx, NUM_TX_DESC |
lea esi, [device.dpd_buffer] |
.txloop: |
test [esi+dpd.frame_start_hdr], 1 shl 31 |
jz .maybenext |
and [esi+dpd.frame_start_hdr], 0 |
push ecx |
stdcall KernelFree, [esi+dpd.realaddr] |
pop ecx |
.maybenext: |
add esi, dpd.size |
dec ecx |
jnz .txloop |
.noTX: |
pop ax |
set_io 0 |
set_io REG_COMMAND |
or ax, AckIntr |
out dx, ax |
set_io REG_INT_STATUS |
in ax, dx |
test ax, S_5_INTS |
jnz .got_it |
;re-enable ints |
set_io REG_COMMAND |
mov ax, SetIntrEnb + S_5_INTS |
out dx, ax |
ret |
; End of code |
align 4 ; Place all initialised data here |
macro strtbl name, [string] |
{ |
common |
label name dword |
forward |
local label |
dd label |
forward |
label db string, 0 |
} |
VORTEX_DEVICES dd 0 |
BOOMERANG_DEVICES dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db '3C59X',0 ; max 16 chars include zero |
strtbl link_str, \ |
"No valid link type detected", \ |
"10BASE-T half duplex", \ |
"10BASE-T full-duplex", \ |
"100BASE-TX half duplex", \ |
"100BASE-TX full duplex", \ |
"100BASE-T4", \ |
"100BASE-FX", \ |
"10Mbps AUI", \ |
"10Mbps COAX (BNC)", \ |
"miiDevice - not supported" |
strtbl hw_str, \ |
"3c590 Vortex 10Mbps", \ |
"3c592 EISA 10Mbps Demon/Vortex", \ |
"3c597 EISA Fast Demon/Vortex", \ |
"3c595 Vortex 100baseTx", \ |
"3c595 Vortex 100baseT4", \ |
"3c595 Vortex 100base-MII", \ |
"3c900 Boomerang 10baseT", \ |
"3c900 Boomerang 10Mbps Combo", \ |
"3c900 Cyclone 10Mbps TPO", \ |
"3c900 Cyclone 10Mbps Combo", \ |
"3c900 Cyclone 10Mbps TPC", \ |
"3c900B-FL Cyclone 10base-FL", \ |
"3c905 Boomerang 100baseTx", \ |
"3c905 Boomerang 100baseT4", \ |
"3c905B Cyclone 100baseTx", \ |
"3c905B Cyclone 10/100/BNC", \ |
"3c905B-FX Cyclone 100baseFx", \ |
"3c905C Tornado", \ |
"3c980 Cyclone", \ |
"3c982 Dual Port Server Cyclone", \ |
"3cSOHO100-TX Hurricane", \ |
"3c555 Laptop Hurricane", \ |
"3c556 Laptop Tornado", \ |
"3c556B Laptop Hurricane", \ |
"3c575 [Megahertz] 10/100 LAN CardBus", \ |
"3c575 Boomerang CardBus", \ |
"3CCFE575BT Cyclone CardBus", \ |
"3CCFE575CT Tornado CardBus", \ |
"3CCFE656 Cyclone CardBus", \ |
"3CCFEM656B Cyclone+Winmodem CardBus", \ |
"3CXFEM656C Tornado+Winmodem CardBus", \ |
"3c450 HomePNA Tornado", \ |
"3c920 Tornado", \ |
"3c982 Hydra Dual Port A", \ |
"3c982 Hydra Dual Port B", \ |
"3c905B-T4", \ |
"3c920B-EMB-WNM Tornado" |
align 4 |
hw_versions: |
dw 0x5900, IS_VORTEX ; 3c590 Vortex 10Mbps |
dw 0x5920, IS_VORTEX ; 3c592 EISA 10Mbps Demon/Vortex |
dw 0x5970, IS_VORTEX ; 3c597 EISA Fast Demon/Vortex |
dw 0x5950, IS_VORTEX ; 3c595 Vortex 100baseTx |
dw 0x5951, IS_VORTEX ; 3c595 Vortex 100baseT4 |
dw 0x5952, IS_VORTEX ; 3c595 Vortex 100base-MII |
dw 0x9000, IS_BOOMERANG ; 3c900 Boomerang 10baseT |
dw 0x9001, IS_BOOMERANG ; 3c900 Boomerang 10Mbps Combo |
dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPO |
dw 0x9005, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps Combo |
dw 0x9006, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPC |
dw 0x900A, IS_CYCLONE or HAS_HWCKSM ; 3c900B-FL Cyclone 10base-FL |
dw 0x9050, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseTx |
dw 0x9051, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseT4 |
dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B Cyclone 100baseTx |
dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c905B Cyclone 10/100/BNC |
dw 0x905A, IS_CYCLONE or HAS_HWCKSM ; 3c905B-FX Cyclone 100baseFx |
dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c905C Tornado |
dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c980 Cyclone |
dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c982 Dual Port Server Cyclone |
dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3cSOHO100-TX Hurricane |
dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM ; 3c555 Laptop Hurricane |
dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM ; 3c556 Laptop Tornado |
dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM ; 3c556B Laptop Hurricane |
dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 [Megahertz] 10/100 LAN CardBus |
dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 Boomerang CardBus |
dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE575BT Cyclone CardBus |
dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CCFE575CT Tornado CardBus |
dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE656 Cyclone CardBus |
dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFEM656B Cyclone+Winmodem CardBus |
dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CXFEM656C Tornado+Winmodem CardBus |
dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c450 HomePNA Tornado |
dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920 Tornado |
dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port A |
dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port B |
dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B-T4 |
dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920B-EMB-WNM Tornado |
HW_VERSIONS_SIZE = $ - hw_versions |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
VORTEX_LIST rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
BOOMERANG_LIST rd MAX_DEVICES |
/kernel/branches/net/drivers/R6040.asm |
---|
0,0 → 1,1111 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; R6040 driver for KolibriOS ;; |
;; ;; |
;; based on R6040.c from linux ;; |
;; ;; |
;; Written by Asper (asper.85@mail.ru) ;; |
;; and hidnplayr (hidnplayr@gmail.com) ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 2 |
W_MAX_TIMEOUT = 0x0FFF ; max time out delay time |
TX_TIMEOUT = 6000 ; Time before concluding the transmitter is hung, in ms |
TX_RING_SIZE = 4 ; RING sizes must be a power of 2 |
RX_RING_SIZE = 4 |
RX_BUF_LEN_IDX = 3 ; 0==8K, 1==16K, 2==32K, 3==64K |
; Threshold is bytes transferred to chip before transmission starts. |
TX_FIFO_THRESH = 256 ; In bytes, rounded down to 32 byte units. |
; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. |
RX_FIFO_THRESH = 4 ; Rx buffer level before first PCI xfer. |
RX_DMA_BURST = 4 ; Maximum PCI burst, '4' is 256 bytes |
TX_DMA_BURST = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
; Operational parameters that usually are not changed. |
PHY1_ADDR = 1 ;For MAC1 |
PHY2_ADDR = 3 ;For MAC2 |
PHY_MODE = 0x3100 ;PHY CHIP Register 0 |
PHY_CAP = 0x01E1 ;PHY CHIP Register 4 |
;************************************************************************** |
; RDC R6040 Register Definitions |
;************************************************************************** |
MCR0 = 0x00 ;Control register 0 |
MCR1 = 0x01 ;Control register 1 |
MAC_RST = 0x0001 ;Reset the MAC |
MBCR = 0x08 ;Bus control |
MT_ICR = 0x0C ;TX interrupt control |
MR_ICR = 0x10 ;RX interrupt control |
MTPR = 0x14 ;TX poll command register |
MR_BSR = 0x18 ;RX buffer size |
MR_DCR = 0x1A ;RX descriptor control |
MLSR = 0x1C ;Last status |
MMDIO = 0x20 ;MDIO control register |
MDIO_WRITE = 0x4000 ;MDIO write |
MDIO_READ = 0x2000 ;MDIO read |
MMRD = 0x24 ;MDIO read data register |
MMWD = 0x28 ;MDIO write data register |
MTD_SA0 = 0x2C ;TX descriptor start address 0 |
MTD_SA1 = 0x30 ;TX descriptor start address 1 |
MRD_SA0 = 0x34 ;RX descriptor start address 0 |
MRD_SA1 = 0x38 ;RX descriptor start address 1 |
MISR = 0x3C ;Status register |
MIER = 0x40 ;INT enable register |
MSK_INT = 0x0000 ;Mask off interrupts |
RX_FINISH = 0x0001 ;RX finished |
RX_NO_DESC = 0x0002 ;No RX descriptor available |
RX_FIFO_FULL = 0x0004 ;RX FIFO full |
RX_EARLY = 0x0008 ;RX early |
TX_FINISH = 0x0010 ;TX finished |
TX_EARLY = 0x0080 ;TX early |
EVENT_OVRFL = 0x0100 ;Event counter overflow |
LINK_CHANGED = 0x0200 ;PHY link changed |
ME_CISR = 0x44 ;Event counter INT status |
ME_CIER = 0x48 ;Event counter INT enable |
MR_CNT = 0x50 ;Successfully received packet counter |
ME_CNT0 = 0x52 ;Event counter 0 |
ME_CNT1 = 0x54 ;Event counter 1 |
ME_CNT2 = 0x56 ;Event counter 2 |
ME_CNT3 = 0x58 ;Event counter 3 |
MT_CNT = 0x5A ;Successfully transmit packet counter |
ME_CNT4 = 0x5C ;Event counter 4 |
MP_CNT = 0x5E ;Pause frame counter register |
MAR0 = 0x60 ;Hash table 0 |
MAR1 = 0x62 ;Hash table 1 |
MAR2 = 0x64 ;Hash table 2 |
MAR3 = 0x66 ;Hash table 3 |
MID_0L = 0x68 ;Multicast address MID0 Low |
MID_0M = 0x6A ;Multicast address MID0 Medium |
MID_0H = 0x6C ;Multicast address MID0 High |
MID_1L = 0x70 ;MID1 Low |
MID_1M = 0x72 ;MID1 Medium |
MID_1H = 0x74 ;MID1 High |
MID_2L = 0x78 ;MID2 Low |
MID_2M = 0x7A ;MID2 Medium |
MID_2H = 0x7C ;MID2 High |
MID_3L = 0x80 ;MID3 Low |
MID_3M = 0x82 ;MID3 Medium |
MID_3H = 0x84 ;MID3 High |
PHY_CC = 0x88 ;PHY status change configuration register |
PHY_ST = 0x8A ;PHY status register |
MAC_SM = 0xAC ;MAC status machine |
MAC_ID = 0xBE ;Identifier register |
MAX_BUF_SIZE = 0x600 ;1536 |
MBCR_DEFAULT = 0x012A ;MAC Bus Control Register |
MCAST_MAX = 3 ;Max number multicast addresses to filter |
;Descriptor status |
DSC_OWNER_MAC = 0x8000 ;MAC is the owner of this descriptor |
DSC_RX_OK = 0x4000 ;RX was successfull |
DSC_RX_ERR = 0x0800 ;RX PHY error |
DSC_RX_ERR_DRI = 0x0400 ;RX dribble packet |
DSC_RX_ERR_BUF = 0x0200 ;RX length exceeds buffer size |
DSC_RX_ERR_LONG = 0x0100 ;RX length > maximum packet length |
DSC_RX_ERR_RUNT = 0x0080 ;RX packet length < 64 byte |
DSC_RX_ERR_CRC = 0x0040 ;RX CRC error |
DSC_RX_BCAST = 0x0020 ;RX broadcast (no error) |
DSC_RX_MCAST = 0x0010 ;RX multicast (no error) |
DSC_RX_MCH_HIT = 0x0008 ;RX multicast hit in hash table (no error) |
DSC_RX_MIDH_HIT = 0x0004 ;RX MID table hit (no error) |
DSC_RX_IDX_MID_MASK = 3 ;RX mask for the index of matched MIDx |
;PHY settings |
ICPLUS_PHY_ID = 0x0243 |
RX_INTS = RX_FIFO_FULL or RX_NO_DESC or RX_FINISH |
TX_INTS = TX_FINISH |
INT_MASK = RX_INTS or TX_INTS |
RX_BUF_LEN equ (8192 << RX_BUF_LEN_IDX) ; Size of the in-memory receive ring. |
IO_SIZE = 256 ; RDC MAC I/O Size |
MAX_MAC = 2 ; MAX RDC MAC |
virtual at 0 |
x_head: |
.status dw ? ;0-1 |
.len dw ? ;2-3 |
.buf dd ? ;4-7 |
.ndesc dd ? ;8-B |
.rev1 dd ? ;C-F |
.vbufp dd ? ;10-13 |
.vndescp dd ? ;14-17 |
.skb_ptr dd ? ;18-1B |
.rev2 dd ? ;1C-1F |
.sizeof: |
end virtual |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.cur_rx dw ? |
.cur_tx dw ? |
.last_tx dw ? |
.phy_addr dw ? |
.phy_mode dw ? |
.mcr0 dw ? |
.mcr1 dw ? |
.switch_sig dw ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
rb 3 ; dword alignment |
.tx_ring: rb (((x_head.sizeof*TX_RING_SIZE)+32) and 0xfffffff0) |
.rx_ring: rb (((x_head.sizeof*RX_RING_SIZE)+32) and 0xfffffff0) |
.size = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Ok, the eth_device structure is ready, let's probe the device |
cli |
call probe ; this function will output in eax |
test eax, eax |
jnz .err_sti ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
sti |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err_sti: |
sti |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
macro mdio_write reg, val { |
stdcall phy_read, [device.io_addr], [device.phy_addr], reg |
} |
macro mdio_write reg, val { |
stdcall phy_write, [device.io_addr], [devce.phy_addr], reg, val |
} |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (RTL8139_LIST) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device (if it really is RTL8139) |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
DEBUGF 2,"Probing R6040 device\n" |
PCI_make_bus_master |
; If PHY status change register is still set to zero |
; it means the bootloader didn't initialize it |
set_io 0 |
set_io PHY_CC |
in ax, dx |
test ax, ax |
jnz @f |
mov ax, 0x9F07 |
out dx, ax |
@@: |
call read_mac |
; Some bootloaders/BIOSes do not initialize MAC address, warn about that |
and eax, 0xFF |
or eax, dword [device.mac] |
test eax, eax |
jnz @f |
DEBUGF 2, "ERROR: MAC address not initialized!\n" |
@@: |
; Init RDC private data |
mov [device.mcr0], 0x1002 |
;mov [private.phy_addr], 1 ; Asper: Only one network card is supported now. |
mov [device.switch_sig], 0 |
; Check the vendor ID on the PHY, if 0xFFFF assume none attached |
stdcall phy_read, 1, 2 |
cmp ax, 0xFFFF |
jne @f |
DEBUGF 2, "Failed to detect an attached PHY\n" ;, generating random" |
mov eax, -1 |
ret |
@@: |
; Set MAC address |
call init_mac_regs |
; Initialize and alloc RX/TX buffers |
call init_txbufs |
call init_rxbufs |
; Read the PHY ID |
mov [device.phy_mode], 0x8000 |
stdcall phy_read, 0, 2 |
mov [device.switch_sig], ax |
cmp ax, ICPLUS_PHY_ID |
jne @f |
stdcall phy_write, 29, 31, 0x175C ; Enable registers |
jmp .phy_readen |
@@: |
; PHY Mode Check |
movzx eax, [device.phy_addr] |
stdcall phy_write, eax, 4, PHY_CAP |
stdcall phy_write, eax, 0, PHY_MODE |
if PHY_MODE = 0x3100 |
call phy_mode_chk |
mov [device.phy_mode], ax |
jmp .phy_readen |
end if |
if not (PHY_MODE and 0x0100) |
mov [device.phy_mode], 0 |
end if |
.phy_readen: |
; Set duplex mode |
mov ax, [device.phy_mode] |
or [device.mcr0], ax |
; improve performance (by RDC guys) |
stdcall phy_read, 30, 17 |
or ax, 0x4000 |
stdcall phy_write, 30, 17, eax |
stdcall phy_read, 30, 17 |
and ax, not 0x2000 |
stdcall phy_write, 30, 17, eax |
stdcall phy_write, 0, 19, 0x0000 |
stdcall phy_write, 0, 30, 0x01F0 |
; Initialize all Mac registers |
call init_mac_regs |
align 4 |
reset: |
DEBUGF 2,"Resetting R6040\n" |
; Mask off Interrupt |
xor ax, ax |
set_io 0 |
set_io MIER |
out dx, ax |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 2,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 2,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
;Reset RDC MAC |
mov eax, MAC_RST |
set_io 0 |
set_io MCR1 |
out dx, ax |
mov ecx, 2048 ;limit |
.read: |
in ax, dx |
test ax, 0x1 |
jnz @f |
dec ecx |
test ecx, ecx |
jnz .read |
@@: |
;Reset internal state machine |
mov ax, 2 |
set_io MAC_SM |
out dx, ax |
xor ax, ax |
out dx, ax |
mov esi, 5 |
stdcall Sleep |
;MAC Bus Control Register |
mov ax, MBCR_DEFAULT |
set_io 0 |
set_io MBCR |
out dx, ax |
;Buffer Size Register |
mov ax, MAX_BUF_SIZE |
set_io MR_BSR |
out dx, ax |
;Write TX ring start address |
lea eax, [device.tx_ring] |
GetRealAddr |
set_io MTD_SA0 |
out dx, ax |
shr eax, 16 |
set_io MTD_SA1 |
out dx, ax |
;Write RX ring start address |
lea eax, [device.rx_ring] |
GetRealAddr |
set_io MRD_SA0 |
out dx, ax |
shr eax, 16 |
set_io MRD_SA1 |
out dx, ax |
;Set interrupt waiting time and packet numbers |
xor ax, ax |
set_io MT_ICR |
out dx, ax |
;Enable interrupts |
mov ax, INT_MASK |
set_io MIER |
out dx, ax |
;Enable TX and RX |
mov ax, [device.mcr0] |
or ax, 0x0002 |
set_io 0 |
out dx, ax |
;Let TX poll the descriptors |
;we may got called by tx_timeout which has left |
;some unset tx buffers |
xor ax, ax |
inc ax |
set_io 0 |
set_io MTPR |
out dx, ax |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
DEBUGF 1,"Reset ok\n" |
xor eax, eax |
ret |
align 4 |
init_txbufs: |
DEBUGF 1,"Init TxBufs\n" |
lea esi, [device.tx_ring] |
lea eax, [device.tx_ring + x_head.sizeof] |
GetRealAddr |
mov ecx, TX_RING_SIZE |
.next_desc: |
mov [esi + x_head.ndesc], eax |
mov [esi + x_head.skb_ptr], 0 |
mov [esi + x_head.status], DSC_OWNER_MAC |
add eax, x_head.sizeof |
add esi, x_head.sizeof |
dec ecx |
jnz .next_desc |
lea eax, [device.tx_ring] |
GetRealAddr |
mov [device.tx_ring + x_head.sizeof*(TX_RING_SIZE - 1) + x_head.ndesc], eax |
ret |
align 4 |
init_rxbufs: |
DEBUGF 1,"Init RxBufs\n" |
lea esi, [device.rx_ring] |
lea eax, [device.rx_ring + x_head.sizeof] |
GetRealAddr |
mov edx, eax |
mov ecx, RX_RING_SIZE |
.next_desc: |
mov [esi + x_head.ndesc], edx |
push esi ecx |
stdcall KernelAlloc, MAX_BUF_SIZE |
pop ecx esi |
mov [esi + x_head.skb_ptr], eax |
GetRealAddr |
mov [esi + x_head.buf], eax |
mov [esi + x_head.status], DSC_OWNER_MAC |
add edx, x_head.sizeof |
add esi, x_head.sizeof |
dec ecx |
jnz .next_desc |
; complete the ring by linking the last to the first |
lea eax, [device.rx_ring] |
GetRealAddr |
mov [device.rx_ring + x_head.sizeof*(RX_RING_SIZE - 1) + x_head.ndesc], eax |
ret |
align 4 |
phy_mode_chk: |
DEBUGF 1,"Checking PHY mode\n" |
; PHY Link Status Check |
movzx eax, [device.phy_addr] |
stdcall phy_read, eax, 1 |
test eax, 0x4 |
jz .ret_0x8000 |
; PHY Chip Auto-Negotiation Status |
movzx eax, [device.phy_addr] |
stdcall phy_read, eax, 1 |
test eax, 0x0020 |
jnz .auto_nego |
; Force Mode |
movzx eax, [device.phy_addr] |
stdcall phy_read, eax, 0 |
test eax, 0x100 |
jnz .ret_0x8000 |
.auto_nego: |
; Auto Negotiation Mode |
movzx eax, [device.phy_addr] |
stdcall phy_read, eax, 5 |
mov ecx, eax |
movzx eax, [device.phy_addr] |
stdcall phy_read, eax, 4 |
and eax, ecx |
test eax, 0x140 |
jnz .ret_0x8000 |
xor eax, eax |
ret |
.ret_0x8000: |
mov eax, 0x8000 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], 1514 |
ja .fail |
cmp dword [esp+8], 60 |
jb .fail |
movzx edi, [device.cur_tx] |
shl edi, 5 |
add edi, ebx |
add edi, device.tx_ring - ebx |
DEBUGF 2,"TX buffer status: 0x%x\n", [edi + x_head.status]:4 |
test [edi + x_head.status], DSC_OWNER_MAC ; check if buffer is available |
jnz .wait_to_send |
.do_send: |
DEBUGF 2,"Sending now\n" |
mov eax, [esp+4] |
mov [edi + x_head.skb_ptr], eax |
GetRealAddr |
mov [edi + x_head.buf], eax |
mov ecx, [esp+8] |
mov [edi + x_head.len], cx |
mov [edi + x_head.status], DSC_OWNER_MAC |
; Trigger the MAC to check the TX descriptor |
mov ax, 0x01 |
set_io 0 |
set_io MTPR |
out dx, ax |
inc [device.cur_tx] |
and [device.cur_tx], TX_RING_SIZE - 1 |
xor eax, eax |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
ret 8 |
.wait_to_send: |
DEBUGF 2,"Waiting for TX buffer\n" |
call GetTimerTicks ; returns in eax |
lea edx, [eax + 100] |
.l2: |
test [edi + x_head.status], DSC_OWNER_MAC |
jz .do_send |
mov esi, 10 |
call Sleep |
call GetTimerTicks |
cmp edx, eax |
jb .l2 |
DEBUGF 1,"Send timeout\n" |
xor eax, eax |
dec eax |
.fail: |
DEBUGF 1,"Send failed\n" |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; Find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io MISR |
in ax, dx |
out dx, ax ; send it back to ACK |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
ret |
; At this point, test for all possible reasons, and handle accordingly |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, ax |
push ax |
test word [esp], RX_FINISH |
jz .no_RX |
push ebx |
.more_RX: |
pop ebx |
; Find the current RX descriptor |
movzx edx, [device.cur_rx] |
shl edx, 5 |
lea edx, [device.rx_ring + edx] |
; Check the descriptor status |
mov cx, [edx + x_head.status] |
test cx, DSC_OWNER_MAC |
jnz .no_RX |
DEBUGF 2,"packet status=0x%x\n", cx |
test cx, DSC_RX_ERR ; Global error status set |
jnz .no_RX |
; Packet successfully received |
movzx ecx, [edx + x_head.len] |
and ecx, 0xFFF |
sub ecx, 4 ; Do not count the CRC |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
; Push packet size and pointer, kernel will need it.. |
push ebx |
push .more_RX |
push ecx |
push [edx + x_head.skb_ptr] |
DEBUGF 2,"packet ptr=0x%x\n", [edx + x_head.skb_ptr] |
; reset the RX descriptor |
push edx |
stdcall KernelAlloc, MAX_BUF_SIZE |
pop edx |
mov [edx + x_head.skb_ptr], eax |
GetRealAddr |
mov [edx + x_head.buf], eax |
mov [edx + x_head.status], DSC_OWNER_MAC |
; Use next descriptor next time |
inc [device.cur_rx] |
and [device.cur_rx], RX_RING_SIZE - 1 |
; At last, send packet to kernel |
jmp Eth_input |
.no_RX: |
test word [esp], TX_FINISH |
jz .no_TX |
.loop_tx: |
movzx edi, [device.last_tx] |
shl edi, 5 |
lea edi, [device.tx_ring + edi] |
test [edi + x_head.status], DSC_OWNER_MAC |
jnz .no_TX |
cmp [edi + x_head.skb_ptr], 0 |
je .no_TX |
DEBUGF 2,"Freeing buffer 0x%x\n", [edi + x_head.skb_ptr] |
push [edi + x_head.skb_ptr] |
mov [edi + x_head.skb_ptr], 0 |
call KernelFree |
inc [device.last_tx] |
and [device.last_tx], TX_RING_SIZE - 1 |
jmp .loop_tx |
.no_TX: |
pop ax |
ret |
align 4 |
init_mac_regs: |
DEBUGF 2,"initializing MAC regs\n" |
; MAC operation register |
mov ax, 1 |
set_io 0 |
set_io MCR1 |
out dx, ax |
; Reset MAC |
mov ax, 2 |
set_io MAC_SM |
out dx, ax |
; Reset internal state machine |
xor ax, ax |
out dx, ax |
mov esi, 5 |
stdcall Sleep |
call read_mac |
ret |
; Read a word data from PHY Chip |
align 4 |
proc phy_read stdcall, phy_addr:dword, reg:dword |
DEBUGF 2,"PHY read, addr=0x%x reg=0x%x\n", [phy_addr]:8, [reg]:8 |
mov eax, [phy_addr] |
shl eax, 8 |
add eax, [reg] |
add eax, MDIO_READ |
set_io 0 |
set_io MMDIO |
out dx, ax |
;Wait for the read bit to be cleared. |
mov ecx, 2048 ;limit |
.read: |
in ax, dx |
test ax, MDIO_READ |
jz @f |
dec ecx |
jnz .read |
@@: |
set_io MMRD |
in ax, dx |
and eax, 0xFFFF |
DEBUGF 2,"PHY read, val=0x%x\n", eax:4 |
ret |
endp |
; Write a word data to PHY Chip |
align 4 |
proc phy_write stdcall, phy_addr:dword, reg:dword, val:dword |
DEBUGF 2,"PHY write, addr=0x%x reg=0x%x val=0x%x\n", [phy_addr]:8, [reg]:8, [val]:8 |
mov eax, [val] |
set_io 0 |
set_io MMWD |
out dx, ax |
;Write the command to the MDIO bus |
mov eax, [phy_addr] |
shl eax, 8 |
add eax, [reg] |
add eax, MDIO_WRITE |
set_io MMDIO |
out dx, ax |
;Wait for the write bit to be cleared. |
mov ecx, 2048 ;limit |
.write: |
in ax, dx |
test ax, MDIO_WRITE |
jz @f |
dec ecx |
jnz .write |
@@: |
DEBUGF 2,"PHY write ok\n" |
ret |
endp |
align 4 |
read_mac: |
DEBUGF 2,"Reading MAC: " |
mov cx, 3 |
lea edi, [device.mac] |
set_io 0 |
set_io MID_0L |
.mac: |
in ax, dx |
stosw |
inc dx |
inc dx |
dec cx |
jnz .mac |
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[edi-6]:2, [edi-5]:2, [edi-4]:2, [edi-3]:2, [edi-2]:2, [edi-1]:2 |
ret |
; End of code |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'R6040',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/RTL8029.asm |
---|
0,0 → 1,1196 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; RTL8029/ne2000 driver for KolibriOS ;; |
;; ;; |
;; based on RTL8029.asm driver for menuetos ;; |
;; and realtek8029.asm for SolarOS by Eugen Brasoveanu ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; with help from CleverMouse ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.irq_line db ? |
.pci_bus dd ? |
.pci_dev dd ? |
.flags db ? |
.vendor db ? |
.memsize db ? |
.rx_start db ? |
.tx_start db ? |
.bmem dd ? |
.rmem dd ? |
.size = $ - device |
end virtual |
public START |
public service_proc |
public version |
P0_COMMAND = 0x00 |
P0_PSTART = 0x01 |
P0_PSTOP = 0x02 |
P0_BOUND = 0x03 |
P0_TSR = 0x04 |
P0_TPSR = 0x04 |
P0_TBCR0 = 0x05 |
P0_TBCR1 = 0x06 |
P0_ISR = 0x07 |
P0_RSAR0 = 0x08 |
P0_RSAR1 = 0x09 |
P0_RBCR0 = 0x0A |
P0_RBCR1 = 0x0B |
P0_RSR = 0x0C |
P0_RCR = 0x0C |
P0_TCR = 0x0D |
P0_DCR = 0x0E |
P0_IMR = 0x0F |
P1_COMMAND = 0x00 |
P1_PAR0 = 0x01 |
P1_PAR1 = 0x02 |
P1_PAR2 = 0x03 |
P1_PAR3 = 0x04 |
P1_PAR4 = 0x05 |
P1_PAR5 = 0x06 |
P1_CURR = 0x07 |
P1_MAR0 = 0x08 |
CMD_PS0 = 0x00 ; Page 0 select |
CMD_PS1 = 0x40 ; Page 1 select |
CMD_PS2 = 0x80 ; Page 2 select |
CMD_RD2 = 0x20 ; Remote DMA control |
CMD_RD1 = 0x10 |
CMD_RD0 = 0x08 |
CMD_TXP = 0x04 ; transmit packet |
CMD_STA = 0x02 ; start |
CMD_STP = 0x01 ; stop |
CMD_RDMA_READ = 001b shl 3 |
CMD_RDMA_WRITE = 010b shl 3 |
CMD_RDMA_SEND_PACKET = 011b shl 3 |
CMD_RDMA_ABORT = 100b shl 3 ; really is 1xx, Abort/Complete Remote DMA |
; RDMA_MASK = 111b shl 3 ; internal, mask |
RCR_MON = 0x20 ; monitor mode |
DCR_FT1 = 0x40 |
DCR_LS = 0x08 ; Loopback select |
DCR_WTS = 0x01 ; Word transfer select |
ISR_PRX = 0x01 ; successful recv |
ISR_PTX = 0x02 ; successful xmit |
ISR_RXE = 0x04 ; receive error |
ISR_TXE = 0x08 ; transmit error |
ISR_OVW = 0x10 ; Overflow |
ISR_CNT = 0x20 ; Counter overflow |
ISR_RDC = 0x40 ; Remote DMA complete |
ISR_RST = 0x80 ; reset |
IRQ_MASK = ISR_PRX ;+ ISR_PTX ;+ ISR_RDC + ISR_PTX + ISR_TXE |
RSTAT_PRX = 1 shl 0 ; successful recv |
RSTAT_CRC = 1 shl 1 ; CRC error |
RSTAT_FAE = 1 shl 2 ; Frame alignment error |
RSTAT_OVER = 1 shl 3 ; FIFO overrun |
TXBUF_SIZE = 6 |
RXBUF_END = 32 |
PAGE_SIZE = 256 |
ETH_ZLEN = 60 |
ETH_FRAME_LEN = 1514 |
FLAG_PIO = 1 shl 0 |
FLAG_16BIT = 1 shl 1 |
VENDOR_NONE = 0 |
VENDOR_WD = 1 |
VENDOR_NOVELL = 2 |
VENDOR_3COM = 3 |
NE_ASIC = 0x10 |
NE_RESET = 0x0F ; Used to reset card |
NE_DATA = 0x00 ; Used to read/write NIC mem |
MEM_8k = 32 |
MEM_16k = 64 |
MEM_32k = 128 |
ISA_MAX_ADDR = 0x400 |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; proc START |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Registering %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; proc SERVICE_PROC |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
;--------------- |
cmp eax, 0 ;SRV_GETVERSION |
jne @F ;--------------- |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: ;--------- |
cmp eax, 1 ;SRV_HOOK |
jne @F ;--------- |
DEBUGF 2,"Checking if device is already listed..\n" |
mov eax, [IOCTL.input] |
cmp [IOCTL.inp_size], 3 |
jb .fail |
cmp byte [eax], 1 |
je .pci |
cmp [IOCTL.inp_size], 4 |
jb .fail |
cmp byte [eax], 0 |
je .isa |
jmp .fail |
.pci: |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice_pci |
mov ax, [eax+1] ; get the pci bus and device numbers |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
.firstdevice_pci: |
call create_new_struct |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
jmp .hook |
.isa: |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice_isa |
mov al, [eax+3] |
movzx edi, word [eax+1] |
.nextdevice_isa: |
mov ebx, [esi] |
cmp edi, [device.io_addr] |
jne .maybenext |
cmp al, [device.irq_line] |
je find_device_num |
.maybenext: |
add esi, 4 |
loop .nextdevice_isa |
.firstdevice_isa: |
call create_new_struct |
mov eax, [IOCTL.input] |
movzx ecx, word [eax+1] |
mov [device.io_addr], ecx |
mov cl, [eax+3] |
mov [device.irq_line], cl |
.hook: |
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] |
mov [device_list+4*eax], ebx |
inc [devices] |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
jz .err |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
.err: |
DEBUGF 1,"Failed, removing device structure\n" |
stdcall KernelFree, ebx |
jmp .fail |
;------------------------------------------------------ |
@@: |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
create_new_struct: |
cmp [devices], MAX_DEVICES |
jae .fail |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
ret |
.fail: |
add esp, 4 ; return to caller of 'hook' |
or eax, -1 |
ret |
find_device_num: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
mov ebx, eax |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
unload: ; TODO |
or eax, -1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device and clears the rx buffer |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
probe: |
mov [device.vendor], VENDOR_NONE |
mov [device.bmem], 0 |
DEBUGF 2,"Trying 16-bit mode\n" |
mov [device.flags], FLAG_16BIT + FLAG_PIO |
mov [device.memsize], MEM_32k |
mov [device.tx_start], 64 |
mov [device.rx_start], TXBUF_SIZE + 64 |
set_io 0 |
set_io P0_DCR |
mov al, DCR_WTS + DCR_FT1 + DCR_LS ; word transfer select + |
out dx, al |
set_io P0_PSTART |
mov al, MEM_16k |
out dx, al |
set_io P0_PSTOP |
mov al, MEM_32k |
out dx, al |
mov esi, my_service |
mov di, 16384 |
mov cx, 14 |
call PIO_write |
mov si, 16384 |
mov cx, 14 |
sub esp, 16 |
mov edi, esp |
call PIO_read |
mov esi, esp |
add esp, 16 |
mov edi, my_service |
mov ecx, 13 |
repe cmpsb |
je ep_set_vendor |
DEBUGF 2,"16-bit mode failed\n" |
DEBUGF 2,"Trying 8-bit mode\n" |
mov [device.flags], FLAG_PIO |
mov [device.memsize], MEM_16k |
mov [device.tx_start], 32 |
mov [device.rx_start], TXBUF_SIZE + 32 |
set_io NE_ASIC + NE_RESET |
in al, dx |
out dx, al |
in al, 0x84 |
set_io P0_COMMAND |
mov al, CMD_RD2 + CMD_STP |
out dx, al |
set_io P0_RCR |
mov al, RCR_MON |
out dx, al |
set_io P0_DCR |
mov al, DCR_FT1 + DCR_LS |
out dx, al |
set_io P0_PSTART |
mov al, MEM_8k |
out dx, al |
set_io P0_PSTOP |
mov al, MEM_16k |
out dx, al |
mov esi, my_service |
mov di, 8192 |
mov cx, 14 |
call PIO_write |
mov si, 8192 |
mov cx, 14 |
sub esp, 16 |
mov edi, esp |
call PIO_read |
mov esi, my_service |
mov edi, esp |
add esp, 16 |
mov ecx, 13 |
repe cmpsb |
je ep_set_vendor |
DEBUGF 2,"This is not a valid ne2000 device!\n" |
or eax, -1 |
ret |
ep_set_vendor: |
DEBUGF 2,"Mode ok\n" |
cmp [device.io_addr], ISA_MAX_ADDR |
jbe .isa |
DEBUGF 2,"Card is using PCI bus\n" |
mov [device.vendor], VENDOR_NOVELL ;;; FIXME |
jmp ep_check_have_vendor |
.isa: |
DEBUGF 2,"Card is using ISA bus\n" |
mov [device.vendor], VENDOR_NOVELL |
ep_check_have_vendor: |
mov al, [device.vendor] |
cmp al, VENDOR_NONE |
; je exit |
cmp al, VENDOR_3COM |
je reset |
mov eax, [device.bmem] |
mov [device.rmem], eax |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; reset: Place the chip into a virgin state |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
reset: |
DEBUGF 2,"Resetting device\n" |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
; Stop card + DMA |
set_io 0 |
; set_io P0_COMMAND |
mov al, CMD_PS0 + CMD_RDMA_ABORT + CMD_STP |
out dx, al |
; initialize DCR |
set_io P0_DCR |
mov al, DCR_FT1 + DCR_LS |
test [device.flags], FLAG_16BIT |
jz @f |
or al, DCR_WTS ; word transfer select |
@@: |
out dx, al |
; clear remote bytes count |
set_io P0_RBCR0 |
xor al, al |
out dx, al |
set_io P0_RBCR1 |
out dx, al |
; initialize Receive configuration register (until all init is done) |
set_io P0_RCR |
mov al, 0x20 ; monitor mode |
out dx, al |
; transmit configuration register to monitor mode (until all ini is done) |
set_io P0_TCR |
mov al, 2 ; internal loopback |
out dx, al |
; clear interupt status |
set_io P0_ISR |
mov al, 0xff |
out dx, al |
; clear IRQ mask ;;;;; CHECKME ;;;;; |
set_io P0_IMR |
xor al, al |
out dx, al |
; set transmit pointer |
set_io P0_TPSR |
mov al, [device.tx_start] |
out dx, al |
; set pagestart pointer |
set_io P0_PSTART |
mov al, [device.rx_start] |
out dx, al |
; set pagestop pointer |
set_io P0_PSTOP |
mov al, [device.memsize] |
out dx, al |
; set boundary pointer |
set_io P0_BOUND |
mov al, [device.memsize] |
dec al |
out dx, al |
; set curr pointer |
set_io P0_COMMAND |
mov al, CMD_PS1 ;+ CMD_RD2 + CMD_STP ; page 1, stop mode |
out dx, al |
set_io P1_CURR |
mov al, [device.rx_start] |
out dx, al |
set_io P0_COMMAND |
mov al, CMD_PS0 ;+ CMD_RD2 + CMD_STA ; go to page 0, start mode |
out dx, al |
; Read MAC address and set it to registers |
call read_mac |
push .macret |
sub esp, 6 |
lea esi, [device.mac] |
mov edi, esp |
movsd |
movsw |
jmp write_mac |
.macret: |
; set IRQ mask |
set_io 0 |
set_io P0_IMR |
mov al, IRQ_MASK |
out dx, al |
; start mode |
set_io P0_COMMAND |
mov al, CMD_STA |
out dx, al |
; clear transmit control register |
set_io P0_TCR |
xor al, al ; no loopback |
out dx, al |
; set receive control register ;;;; |
set_io P0_RCR |
mov al, 4 ; accept broadcast |
out dx, al |
; clear packet/byte counters |
xor eax, eax |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], ETH_FRAME_LEN |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
; Indicate that we have successfully reset the card |
xor eax, eax |
DEBUGF 2,"Done!\n" |
ret |
;*************************************************************************** |
; Function |
; transmit |
; buffer in [esp+4], size in [esp+8], pointer to device struct in ebx |
;*************************************************************************** |
align 4 |
transmit: |
mov esi, [esp + 4] |
mov ecx, [esp + 8] |
DEBUGF 2,"Transmitting packet, buffer:%x, size:%u\n",esi, ecx |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[esi+0]:2,[esi+1]:2,[esi+2]:2,[esi+3]:2,[esi+4]:2,[esi+5]:2,[esi+6]:2,[esi+7]:2,[esi+8]:2,[esi+9]:2,[esi+10]:2,[esi+11]:2,[esi+13]:2,[esi+12]:2 |
cmp ecx, ETH_FRAME_LEN |
ja .err ; packet is too long |
cmp ecx, ETH_ZLEN |
jb .err ; packet is too short |
movzx edi, [device.tx_start] |
shl edi, 8 |
push cx |
call PIO_write |
pop cx |
set_io 0 |
; set_io P0_COMMAND |
mov al, CMD_PS0 + CMD_RD2 + CMD_STA |
out dx, al |
set_io P0_TPSR |
mov al, [device.tx_start] |
out dx, al |
set_io P0_TBCR0 |
mov al, cl |
out dx, al |
set_io P0_TBCR1 |
mov al, ch |
out dx, al |
set_io P0_COMMAND |
mov al, CMD_PS0 + CMD_TXP + CMD_RD2 + CMD_STA |
out dx, al |
DEBUGF 2," - Packet Sent!\n" |
inc [device.packets_tx] |
mov eax, [esp + 8] ; Get packet size in eax |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
stdcall KernelFree, [esp+4] |
xor eax, eax |
ret 8 |
.err: |
DEBUGF 2," - Error!\n" |
or eax, -1 |
stdcall KernelFree, [esp+4] |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; |
; Interrupt handler |
; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made INT occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
; set_io P0_COMMAND |
mov al, CMD_PS0 |
out dx, al |
set_io P0_ISR |
in al, dx |
test al, al |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret |
.got_it: |
DEBUGF 1,"Device=%x status=%x\n", ebx, eax:2 |
push ebx |
test al, ISR_PRX ; packet received ok ? |
jz .no_rx |
test [device.flags], FLAG_PIO |
jz .no_rx ; FIXME: Only PIO mode supported for now |
; |
pushd .no_rx |
; allocate a buffer |
stdcall KernelAlloc, ETH_FRAME_LEN |
test eax, eax |
jz .fail_2 |
pushd 0 |
push eax |
; read offset for current packet from device |
set_io 0 |
set_io P0_BOUND ; boundary ptr is offset to next packet we need to read. |
in al, dx |
inc al |
cmp al, [device.memsize] |
jb @f |
mov al, [device.rx_start] |
@@: |
mov ch, al |
set_io P0_COMMAND |
mov al, CMD_PS1 |
out dx, al |
set_io P1_CURR |
in al, dx ; get current page in cl |
mov cl, al |
set_io P1_COMMAND |
mov al, CMD_PS0 |
out dx, al |
cmp cl, [device.memsize] |
jb @f |
mov cl, [device.rx_start] |
@@: |
cmp cl, ch |
je .fail |
movzx esi, ch ; we are using 256 byte pages |
shl esi, 8 ; esi now holds the offset for current packet |
; Get packet header in eax |
sub esp, 4 ; reserve 4 bytes on stack to put packet header in |
mov edi, esp |
mov cx, 4 |
call PIO_read |
mov ecx, [esp] ; ecx now contains packet header |
; check if packet is ok |
test ecx, RSTAT_PRX |
jz .fail_3 |
; calculate packet length in ecx |
shr ecx, 16 |
sub ecx, 4 ; CRC doesnt count as data byte |
mov [esp + 4 + 4], ecx |
; check if packet size is ok |
cmp ecx, ETH_ZLEN |
jb .fail_3 |
cmp ecx, ETH_FRAME_LEN |
ja .fail_3 |
; update stats |
DEBUGF 2,"Received %u bytes\n", ecx |
add dword[device.bytes_rx], ecx |
adc dword[device.bytes_rx + 4], 0 |
inc [device.packets_rx] |
; update read and write pointers |
add esi, 4 |
mov edi, [esp + 4] |
; now check if we can read all data at once (if we cross the end boundary, we need to wrap back to the beginning) |
xor eax, eax |
mov ah, [device.memsize] |
sub eax, esi |
cmp ecx, eax ; eax = number of bytes till end of buffer, ecx = bytes we need to read |
jbe .no_wrap |
DEBUGF 2,"WRAP!\n" |
; Read first part |
sub ecx, eax |
push ecx |
mov ecx, eax |
call PIO_read ; Read the data |
; update pointers |
add edi, ecx |
pop ecx |
movzx esi, [device.rx_start] |
shl esi, 8 |
; now read second part (or only part) |
.no_wrap: |
call PIO_read ; Read the data |
; update boundary pointer |
pop eax |
mov al, ah |
cmp al, [device.rx_start] |
jne @f |
mov al, [device.memsize] |
@@: |
set_io 0 |
set_io P0_BOUND |
dec al |
out dx, al |
; now send the data to the kernel |
jmp Eth_input |
.fail_3: |
add esp, 4 |
.fail: |
add esp, 8 |
.fail_2: |
.no_rx: |
pop ebx |
DEBUGF 2,"done\n" |
set_io 0 |
set_io P0_ISR |
mov al, 0xff |
out dx, al |
ret |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Write MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
write_mac: ; in: mac on stack (6 bytes) |
DEBUGF 1,"Writing MAC\n" |
set_io 0 |
mov al, CMD_PS1; + CMD_RD2 + CMD_STP |
out dx, al |
set_io P1_PAR0 |
mov esi, esp |
mov cx, 6 |
@@: |
lodsb |
out dx, al |
inc dx |
loopw @r |
add esp, 6 |
; Notice this procedure does not ret, but continues to read_mac instead. |
;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Read MAC address ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;; |
read_mac: |
DEBUGF 1,"Reading MAC\n" |
xor esi, esi |
mov cx, 16 |
sub esp, 16 |
mov edi, esp |
call PIO_read |
mov esi, esp |
add esp, 16 |
lea edi, [device.mac] |
mov ecx, 6 |
.loop: |
movsb |
test [device.flags], FLAG_16BIT |
jz .8bit |
inc esi |
.8bit: |
loop .loop |
DEBUGF 1,"MAC=%x-%x-%x-%x-%x-%x\n",\ |
[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;*************************************************************************** |
; |
; PIO_read |
; |
; Description |
; Read a frame from the ethernet card via Programmed I/O |
; src in si |
; cnt in cx |
; dst in edi |
;*************************************************************************** |
PIO_read: |
DEBUGF 1,"PIO Read from %x to %x, %u bytes ", si, edi, cx |
; start DMA |
set_io 0 |
; set_io P0_COMMAND |
mov al, CMD_RD2 + CMD_STA |
out dx, al |
; set length of data we're interested in |
set_io P0_RBCR0 |
mov al, cl |
out dx, al |
set_io P0_RBCR1 |
mov al, ch |
out dx, al |
; set offset of what we want to read |
set_io P0_RSAR0 |
mov ax, si |
out dx, al |
set_io P0_RSAR1 |
shr ax, 8 |
out dx, al |
; start DMA read |
set_io P0_COMMAND |
mov al, CMD_RD0 + CMD_STA |
out dx, al |
set_io NE_ASIC |
test [device.flags], FLAG_16BIT |
jz .8bits |
DEBUGF 1,"(16-bit mode)\n" |
shr cx, 1 ; note that if the number was odd, carry flag will be set |
pushf |
.16bits: |
in ax, dx |
stosw |
loopw .16bits |
inc cx |
popf |
jnc .done |
jmp .8bits_ |
.8bits: |
DEBUGF 1,"(8-bit mode)\n" |
.8bits_: |
in al, dx |
stosb |
loopw .8bits_ |
.done: |
; set_io 0 |
; set_io P0_ISR |
; |
; .dmawait: ; Wait for Remote DMA Complete |
; in al, dx |
; test al, ISR_RDC |
; jz .dmawait |
; and al, not ISR_RDC |
; out dx, al ; clear the bit |
ret |
;*************************************************************************** |
; |
; PIO_write |
; |
; Description |
; writes a frame to the ethernet card via Programmed I/O |
; dst in di |
; cnt in cx |
; src in esi |
;*************************************************************************** |
PIO_write: |
DEBUGF 1,"Eth PIO Write from %x to %x, %u bytes ", esi, di, cx |
set_io 0 |
; set_io P0_COMMAND |
mov al, CMD_RD2 + CMD_STA |
out dx, al |
set_io P0_ISR |
mov al, ISR_RDC |
out dx, al |
set_io P0_RBCR0 |
mov al, cl |
out dx, al |
set_io P0_RBCR1 |
mov al, ch |
out dx, al |
mov ax, di |
set_io P0_RSAR0 |
out dx, al |
shr ax, 8 |
set_io P0_RSAR1 |
out dx, al |
set_io P0_COMMAND |
mov al, CMD_RD1 + CMD_STA |
out dx, al |
set_io NE_ASIC |
test [device.flags], FLAG_16BIT |
jz .8_bit |
DEBUGF 1,"(16-bit mode)\n" |
shr cx, 1 ; note that if the number was odd, carry flag will be set |
pushf ; save the flags for later |
.16bit: |
lodsw |
out dx, ax |
loopw .16bit |
popf |
jnc .done |
inc cx |
jmp .8_bit_ |
.8_bit: |
DEBUGF 1,"(8-bit mode)\n" |
.8_bit_: |
lodsb |
out dx, al |
loopw .8_bit_ |
.done: |
; set_io 0 |
; set_io P0_ISR |
; .dmawait: ; Wait for Remote DMA Complete |
; in al, dx |
; test al, ISR_RDC |
; jz .dmawait |
; and al, not ISR_RDC |
; out dx, al ; clear the bit |
ret |
;all initialized data place here |
align 4 |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'RTL8029/ne2000',0 ;max 16 chars include zero |
;device_1 db 'Realtek 8029',0 |
;device_2 db 'Realtek 8019',0 |
;device_3 db 'Realtek 8019AS',0 |
;device_4 db 'ne2000',0 |
;device_5 db 'DP8390',0 |
include_debug_strings |
section '.data' data readable writable align 16 ;place all uninitialized data place here |
device_list rd MAX_DEVICES |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/RTL8169.asm |
---|
0,0 → 1,1315 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; RTL8169 driver for KolibriOS ;; |
;; ;; |
;; Copyright 2007 mike.dld, ;; |
;; mike.dld@gmail.com ;; |
;; ;; |
;; port to net branch by hidnplayr ;; |
;; ;; |
;; References: ;; |
;; r8169.c - linux driver (etherboot project) ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
NUM_TX_DESC = 4 |
NUM_RX_DESC = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
REG_MAC0 = 0x0 ; Ethernet hardware address |
REG_MAR0 = 0x8 ; Multicast filter |
REG_TxDescStartAddr = 0x20 |
REG_TxHDescStartAddr = 0x28 |
REG_FLASH = 0x30 |
REG_ERSR = 0x36 |
REG_ChipCmd = 0x37 |
REG_TxPoll = 0x38 |
REG_IntrMask = 0x3C |
REG_IntrStatus = 0x3E |
REG_TxConfig = 0x40 |
REG_RxConfig = 0x44 |
REG_RxMissed = 0x4C |
REG_Cfg9346 = 0x50 |
REG_Config0 = 0x51 |
REG_Config1 = 0x52 |
REG_Config2 = 0x53 |
REG_Config3 = 0x54 |
REG_Config4 = 0x55 |
REG_Config5 = 0x56 |
REG_MultiIntr = 0x5C |
REG_PHYAR = 0x60 |
REG_TBICSR = 0x64 |
REG_TBI_ANAR = 0x68 |
REG_TBI_LPAR = 0x6A |
REG_PHYstatus = 0x6C |
REG_RxMaxSize = 0xDA |
REG_CPlusCmd = 0xE0 |
REG_RxDescStartAddr = 0xE4 |
REG_ETThReg = 0xEC |
REG_FuncEvent = 0xF0 |
REG_FuncEventMask = 0xF4 |
REG_FuncPresetState = 0xF8 |
REG_FuncForceEvent = 0xFC |
; InterruptStatusBits |
ISB_SYSErr = 0x8000 |
ISB_PCSTimeout = 0x4000 |
ISB_SWInt = 0x0100 |
ISB_TxDescUnavail = 0x80 |
ISB_RxFIFOOver = 0x40 |
ISB_LinkChg = 0x20 |
ISB_RxOverflow = 0x10 |
ISB_TxErr = 0x08 |
ISB_TxOK = 0x04 |
ISB_RxErr = 0x02 |
ISB_RxOK = 0x01 |
; RxStatusDesc |
SD_RxRES = 0x00200000 |
SD_RxCRC = 0x00080000 |
SD_RxRUNT = 0x00100000 |
SD_RxRWT = 0x00400000 |
; ChipCmdBits |
CMD_Reset = 0x10 |
CMD_RxEnb = 0x08 |
CMD_TxEnb = 0x04 |
CMD_RxBufEmpty = 0x01 |
; Cfg9346Bits |
CFG_9346_Lock = 0x00 |
CFG_9346_Unlock = 0xC0 |
; rx_mode_bits |
RXM_AcceptErr = 0x20 |
RXM_AcceptRunt = 0x10 |
RXM_AcceptBroadcast = 0x08 |
RXM_AcceptMulticast = 0x04 |
RXM_AcceptMyPhys = 0x02 |
RXM_AcceptAllPhys = 0x01 |
; RxConfigBits |
RXC_FIFOShift = 13 |
RXC_DMAShift = 8 |
; TxConfigBits |
TXC_InterFrameGapShift = 24 |
TXC_DMAShift = 8 ; DMA burst value (0-7) is shift this many bits |
; PHYstatus |
PHYS_TBI_Enable = 0x80 |
PHYS_TxFlowCtrl = 0x40 |
PHYS_RxFlowCtrl = 0x20 |
PHYS_1000bpsF = 0x10 |
PHYS_100bps = 0x08 |
PHYS_10bps = 0x04 |
PHYS_LinkStatus = 0x02 |
PHYS_FullDup = 0x01 |
; GIGABIT_PHY_registers |
PHY_CTRL_REG = 0 |
PHY_STAT_REG = 1 |
PHY_AUTO_NEGO_REG = 4 |
PHY_1000_CTRL_REG = 9 |
; GIGABIT_PHY_REG_BIT |
PHY_Restart_Auto_Nego = 0x0200 |
PHY_Enable_Auto_Nego = 0x1000 |
; PHY_STAT_REG = 1 |
PHY_Auto_Neco_Comp = 0x0020 |
; PHY_AUTO_NEGO_REG = 4 |
PHY_Cap_10_Half = 0x0020 |
PHY_Cap_10_Full = 0x0040 |
PHY_Cap_100_Half = 0x0080 |
PHY_Cap_100_Full = 0x0100 |
; PHY_1000_CTRL_REG = 9 |
PHY_Cap_1000_Full = 0x0200 |
PHY_Cap_1000_Half = 0x0100 |
PHY_Cap_PAUSE = 0x0400 |
PHY_Cap_ASYM_PAUSE = 0x0800 |
PHY_Cap_Null = 0x0 |
; _MediaType |
MT_10_Half = 0x01 |
MT_10_Full = 0x02 |
MT_100_Half = 0x04 |
MT_100_Full = 0x08 |
MT_1000_Full = 0x10 |
; _TBICSRBit |
TBI_LinkOK = 0x02000000 |
; _DescStatusBit |
DSB_OWNbit = 0x80000000 |
DSB_EORbit = 0x40000000 |
DSB_FSbit = 0x20000000 |
DSB_LSbit = 0x10000000 |
RX_BUF_SIZE = 1536 ; Rx Buffer size |
; max supported gigabit ethernet frame size -- must be at least (dev->mtu+14+4) |
MAX_ETH_FRAME_SIZE = 1536 |
TX_FIFO_THRESH = 256 ; In bytes |
RX_FIFO_THRESH = 7 ; 7 means NO threshold, Rx buffer level before first PCI xfer |
RX_DMA_BURST = 7 ; Maximum PCI burst, '6' is 1024 |
TX_DMA_BURST = 7 ; Maximum PCI burst, '6' is 1024 |
ETTh = 0x3F ; 0x3F means NO threshold |
EarlyTxThld = 0x3F ; 0x3F means NO early transmit |
RxPacketMaxSize = 0x0800 ; Maximum size supported is 16K-1 |
InterFrameGap = 0x03 ; 3 means InterFrameGap = the shortest one |
HZ = 1000 |
RTL_MIN_IO_SIZE = 0x80 |
TX_TIMEOUT = (6*HZ) |
TIMER_EXPIRE_TIME = 100 |
ETH_HDR_LEN = 14 |
DEFAULT_MTU = 1500 |
DEFAULT_RX_BUF_LEN = 1536 |
;ifdef JUMBO_FRAME_SUPPORT |
; MAX_JUMBO_FRAME_MTU = 10000 |
; MAX_RX_SKBDATA_SIZE = (MAX_JUMBO_FRAME_MTU + ETH_HDR_LEN ) |
;else |
MAX_RX_SKBDATA_SIZE = 1600 |
;end if |
MCFG_METHOD_01 = 0x01 |
MCFG_METHOD_02 = 0x02 |
MCFG_METHOD_03 = 0x03 |
MCFG_METHOD_04 = 0x04 |
MCFG_METHOD_05 = 0x05 |
MCFG_METHOD_11 = 0x0b |
MCFG_METHOD_12 = 0x0c |
MCFG_METHOD_13 = 0x0d |
MCFG_METHOD_14 = 0x0e |
MCFG_METHOD_15 = 0x0f |
PCFG_METHOD_1 = 0x01 ; PHY Reg 0x03 bit0-3 == 0x0000 |
PCFG_METHOD_2 = 0x02 ; PHY Reg 0x03 bit0-3 == 0x0001 |
PCFG_METHOD_3 = 0x03 ; PHY Reg 0x03 bit0-3 == 0x0002 |
virtual at 0 |
tx_desc: |
.status dd ? |
.vlan_tag dd ? |
.buf_addr dq ? |
.size = $ |
rb (NUM_TX_DESC-1)*tx_desc.size |
.buf_soft_addr dd ? |
end virtual |
virtual at 0 |
rx_desc: |
.status dd ? |
.vlan_tag dd ? |
.buf_addr dq ? |
.size = $ |
rb (NUM_RX_DESC-1)*rx_desc.size |
.buf_soft_addr dd ? |
end virtual |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
rb 256-(($ - device) and 255) ; align 256 |
.tx_ring rb NUM_TX_DESC * tx_desc.size * 2 |
rb 256-(($ - device) and 255) ; align 256 |
.rx_ring rb NUM_RX_DESC * rx_desc.size * 2 |
tpc: |
.mmio_addr dd ? ; memory map physical address |
.chipset dd ? |
.pcfg dd ? |
.mcfg dd ? |
.cur_rx dd ? ; Index into the Rx descriptor buffer of next Rx pkt |
.cur_tx dd ? ; Index into the Tx descriptor buffer of next Rx pkt |
.TxDescArrays dd ? ; Index of Tx Descriptor buffer |
.RxDescArrays dd ? ; Index of Rx Descriptor buffer |
.TxDescArray dd ? ; Index of 256-alignment Tx Descriptor buffer |
.RxDescArray dd ? ; Index of 256-alignment Rx Descriptor buffer |
device_size = $ - device |
end virtual |
intr_mask = ISB_LinkChg or ISB_RxOverflow or ISB_RxFIFOOver or ISB_TxErr or ISB_TxOK or ISB_RxErr or ISB_RxOK |
rx_config = (RX_FIFO_THRESH shl RXC_FIFOShift) or (RX_DMA_BURST shl RXC_DMAShift) or 0x0000000E |
macro udelay msec { |
push esi |
mov esi, msec |
call Sleep |
pop esi |
} |
macro WRITE_GMII_REG RegAddr, value { |
set_io REG_PHYAR |
if value eq ax |
and eax, 0x0000ffff |
or eax, 0x80000000 + (RegAddr shl 16) |
else |
mov eax, 0x80000000 + (RegAddr shl 16) + value |
end if |
out dx, eax |
call PHY_WAIT_WRITE |
} |
macro READ_GMII_REG RegAddr { |
local .error, .done |
set_io REG_PHYAR |
mov eax, RegAddr shl 16 |
out dx, eax |
call PHY_WAIT_READ |
jz .error |
in eax, dx |
and eax, 0xFFFF |
jmp .done |
.error: |
or eax, -1 |
.done: |
} |
align 4 |
PHY_WAIT_READ: ; io addr must already be set to REG_PHYAR |
udelay 1 ;;;1000 |
push ecx |
mov ecx, 2000 |
; Check if the RTL8169 has completed writing/reading to the specified MII register |
@@: |
in eax, dx |
test eax, 0x80000000 |
jnz .exit |
udelay 1 ;;;100 |
loop @b |
.exit: |
pop ecx |
ret |
align 4 |
PHY_WAIT_WRITE: ; io addr must already be set to REG_PHYAR |
udelay 1 ;;;1000 |
push ecx |
mov ecx, 2000 |
; Check if the RTL8169 has completed writing/reading to the specified MII register |
@@: |
in eax, dx |
test eax, 0x80000000 |
jz .exit |
udelay 1 ;;;100 |
loop @b |
.exit: |
pop ecx |
ret |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device_size, .fail ; Allocate memory to put the device structure in |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
mov [tpc.mmio_addr], eax ; CHECKME |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 |
; Ok, the eth_device structure is ready, let's probe the device |
; Because initialization fires IRQ, IRQ handler must be aware of this device |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list + 4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
call probe ; this function will output in eax |
test eax, eax |
jnz .err2 ; If an error occured, exit |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 2,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err2: |
dec [devices] |
.err: |
DEBUGF 2,"removing device structure\n" |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
align 4 |
unload: |
ret |
align 4 |
init_board: |
DEBUGF 1,"init_board\n" |
PCI_make_bus_master |
; Soft reset the chip |
set_io 0 |
set_io REG_ChipCmd |
mov al, CMD_Reset |
out dx, al |
; Check that the chip has finished the reset |
mov ecx, 1000 |
set_io REG_ChipCmd |
@@: in al, dx |
test al, CMD_Reset |
jz @f |
udelay 10 |
loop @b |
@@: |
; identify config method |
set_io REG_TxConfig |
in eax, dx |
and eax, 0x7c800000 |
DEBUGF 1,"init_board: TxConfig & 0x7c800000 = 0x%x\n", eax |
mov esi, mac_info-8 |
@@: add esi, 8 |
mov ecx, eax |
and ecx, [esi] |
cmp ecx, [esi] |
jne @b |
mov eax, [esi+4] |
mov [tpc.mcfg], eax |
mov [tpc.pcfg], PCFG_METHOD_3 |
READ_GMII_REG 3 |
and al, 0x0f |
or al, al |
jnz @f |
mov [tpc.pcfg], PCFG_METHOD_1 |
jmp .pconf |
@@: dec al |
jnz .pconf |
mov [tpc.pcfg], PCFG_METHOD_2 |
.pconf: |
; identify chip attached to board |
mov ecx, 10 |
mov eax, [tpc.mcfg] |
@@: dec ecx |
js @f |
cmp eax, [rtl_chip_info + ecx*8] |
jne @b |
mov [tpc.chipset], ecx |
jmp .match |
@@: |
; if unknown chip, assume array element #0, original RTL-8169 in this case |
DEBUGF 1,"init_board: PCI device: unknown chip version, assuming RTL-8169\n" |
set_io REG_TxConfig |
in eax, dx |
DEBUGF 1,"init_board: PCI device: TxConfig = 0x%x\n", eax |
mov [tpc.chipset], 0 |
xor eax, eax |
inc eax |
ret |
.match: |
DEBUGF 1,"init_board: chipset=%u\n", ecx |
xor eax,eax |
ret |
;*************************************************************************** |
; Function |
; probe |
; Description |
; Searches for an ethernet card, enables it and clears the rx buffer |
; If a card was found, it enables the ethernet -> TCPIP link |
; Destroyed registers |
; eax, ebx, ecx, edx |
; |
;*************************************************************************** |
align 4 |
probe: |
DEBUGF 1,"probe\n" |
call init_board |
call read_mac |
call PHY_config |
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" |
set_io 0 |
set_io 0x82 |
mov al, 0x01 |
out dx, al |
cmp [tpc.mcfg], MCFG_METHOD_03 |
jae @f |
; DEBUGF 1,"K : Set PCI Latency=0x40\n" |
; stdcall pci_write_config_byte,PCI_LATENCY_TIMER,0x40 |
@@: |
cmp [tpc.mcfg], MCFG_METHOD_02 |
jne @f |
; DEBUGF 1,"K : Set MAC Reg C+CR Offset 0x82h = 0x01h\n" |
set_io 0x82 |
mov al, 0x01 |
out dx, al |
; DEBUGF 1,"K : Set PHY Reg 0x0bh = 0x00h\n" |
WRITE_GMII_REG 0x0b, 0x0000 ; w 0x0b 15 0 0 |
@@: |
; if TBI is not enabled |
set_io 0 |
set_io REG_PHYstatus |
in al, dx |
test al, PHYS_TBI_Enable |
jz .tbi_dis |
READ_GMII_REG PHY_AUTO_NEGO_REG |
; enable 10/100 Full/Half Mode, leave PHY_AUTO_NEGO_REG bit4:0 unchanged |
and eax, 0x0C1F |
or eax, PHY_Cap_10_Half or PHY_Cap_10_Full or PHY_Cap_100_Half or PHY_Cap_100_Full |
WRITE_GMII_REG PHY_AUTO_NEGO_REG, ax |
; enable 1000 Full Mode |
WRITE_GMII_REG PHY_1000_CTRL_REG, PHY_Cap_1000_Full or PHY_Cap_1000_Half ; rtl8168 |
; Enable auto-negotiation and restart auto-nigotiation |
WRITE_GMII_REG PHY_CTRL_REG, PHY_Enable_Auto_Nego or PHY_Restart_Auto_Nego |
udelay 100 |
mov ecx, 10000 |
; wait for auto-negotiation process |
@@: dec ecx |
jz @f |
set_io 0 |
READ_GMII_REG PHY_STAT_REG |
udelay 100 |
test eax, PHY_Auto_Neco_Comp |
jz @b |
set_io REG_PHYstatus |
in al, dx |
jmp @f |
.tbi_dis: |
udelay 100 |
@@: |
;*************************************************************************** |
; Function |
; rt8169_reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; Destroyed registers |
; eax, ebx, ecx, edx |
; |
;*************************************************************************** |
align 4 |
reset: |
DEBUGF 1,"reset\n" |
lea eax, [device.tx_ring] |
mov [tpc.TxDescArrays], eax |
mov [tpc.TxDescArray], eax |
lea eax, [device.rx_ring] |
mov [tpc.RxDescArrays], eax |
mov [tpc.RxDescArray], eax |
call init_ring |
call hw_start |
; clear packet/byte counters |
xor eax, eax |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
mov [device.mtu], 1500 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
xor eax, eax |
ret |
align 4 |
PHY_config: |
DEBUGF 1,"hw_PHY_config: priv.mcfg=%d, priv.pcfg=%d\n",[tpc.mcfg],[tpc.pcfg] |
cmp [tpc.mcfg], MCFG_METHOD_04 |
jne .not_4 |
set_io 0 |
; WRITE_GMII_REG 0x1F, 0x0001 |
; WRITE_GMII_REG 0x1b, 0x841e |
; WRITE_GMII_REG 0x0e, 0x7bfb |
; WRITE_GMII_REG 0x09, 0x273a |
WRITE_GMII_REG 0x1F, 0x0002 |
WRITE_GMII_REG 0x01, 0x90D0 |
WRITE_GMII_REG 0x1F, 0x0000 |
jmp .exit |
.not_4: |
cmp [tpc.mcfg], MCFG_METHOD_02 |
je @f |
cmp [tpc.mcfg], MCFG_METHOD_03 |
jne .not_2_or_3 |
@@: |
set_io 0 |
WRITE_GMII_REG 0x1F, 0x0001 |
WRITE_GMII_REG 0x15, 0x1000 |
WRITE_GMII_REG 0x18, 0x65C7 |
WRITE_GMII_REG 0x04, 0x0000 |
WRITE_GMII_REG 0x03, 0x00A1 |
WRITE_GMII_REG 0x02, 0x0008 |
WRITE_GMII_REG 0x01, 0x1020 |
WRITE_GMII_REG 0x00, 0x1000 |
WRITE_GMII_REG 0x04, 0x0800 |
WRITE_GMII_REG 0x04, 0x0000 |
WRITE_GMII_REG 0x04, 0x7000 |
WRITE_GMII_REG 0x03, 0xFF41 |
WRITE_GMII_REG 0x02, 0xDE60 |
WRITE_GMII_REG 0x01, 0x0140 |
WRITE_GMII_REG 0x00, 0x0077 |
WRITE_GMII_REG 0x04, 0x7800 |
WRITE_GMII_REG 0x04, 0x7000 |
WRITE_GMII_REG 0x04, 0xA000 |
WRITE_GMII_REG 0x03, 0xDF01 |
WRITE_GMII_REG 0x02, 0xDF20 |
WRITE_GMII_REG 0x01, 0xFF95 |
WRITE_GMII_REG 0x00, 0xFA00 |
WRITE_GMII_REG 0x04, 0xA800 |
WRITE_GMII_REG 0x04, 0xA000 |
WRITE_GMII_REG 0x04, 0xB000 |
WRITE_GMII_REG 0x03, 0xFF41 |
WRITE_GMII_REG 0x02, 0xDE20 |
WRITE_GMII_REG 0x01, 0x0140 |
WRITE_GMII_REG 0x00, 0x00BB |
WRITE_GMII_REG 0x04, 0xB800 |
WRITE_GMII_REG 0x04, 0xB000 |
WRITE_GMII_REG 0x04, 0xF000 |
WRITE_GMII_REG 0x03, 0xDF01 |
WRITE_GMII_REG 0x02, 0xDF20 |
WRITE_GMII_REG 0x01, 0xFF95 |
WRITE_GMII_REG 0x00, 0xBF00 |
WRITE_GMII_REG 0x04, 0xF800 |
WRITE_GMII_REG 0x04, 0xF000 |
WRITE_GMII_REG 0x04, 0x0000 |
WRITE_GMII_REG 0x1F, 0x0000 |
WRITE_GMII_REG 0x0B, 0x0000 |
jmp .exit |
.not_2_or_3: |
DEBUGF 1,"tpc.mcfg=%d, discard hw PHY config\n", [tpc.mcfg] |
.exit: |
ret |
align 4 |
set_rx_mode: |
DEBUGF 1,"set_rx_mode\n" |
; IFF_ALLMULTI |
; Too many to filter perfectly -- accept all multicasts |
set_io 0 |
set_io REG_RxConfig |
in eax, dx |
mov ecx, [tpc.chipset] |
and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask |
or eax, rx_config or (RXM_AcceptBroadcast or RXM_AcceptMulticast or RXM_AcceptMyPhys) |
out dx, eax |
; Multicast hash filter |
set_io REG_MAR0 + 0 |
or eax, -1 |
out dx, eax |
set_io REG_MAR0 + 4 |
out dx, eax |
ret |
align 4 |
init_ring: |
DEBUGF 1,"init_ring\n" |
xor eax, eax |
mov [tpc.cur_rx], eax |
mov [tpc.cur_tx], eax |
lea edi, [device.tx_ring] |
mov ecx, (NUM_TX_DESC * tx_desc.size) / 4 |
rep stosd |
lea edi, [device.rx_ring] |
mov ecx, (NUM_RX_DESC * rx_desc.size) / 4 |
rep stosd |
mov edi, [tpc.RxDescArray] |
mov ecx, NUM_RX_DESC |
.loop: |
push ecx |
stdcall KernelAlloc, RX_BUF_SIZE |
mov [edi + rx_desc.buf_soft_addr], eax |
call GetPgAddr |
mov dword [edi + rx_desc.buf_addr], eax |
mov [edi + rx_desc.status], DSB_OWNbit or RX_BUF_SIZE |
add edi, rx_desc.size |
pop ecx |
loop .loop |
or [edi - rx_desc.size + rx_desc.status], DSB_EORbit |
ret |
align 4 |
hw_start: |
DEBUGF 1,"hw_start\n" |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
; Soft reset the chip |
set_io 0 |
set_io REG_ChipCmd |
mov al, CMD_Reset |
out dx, al |
DEBUGF 1,"Waiting for chip to reset... " |
; Check that the chip has finished the reset |
mov ecx, 1000 |
set_io REG_ChipCmd |
@@: in al, dx |
test al, CMD_Reset |
jz @f |
udelay 10 |
loop @b |
@@: |
DEBUGF 1,"done!\n" |
set_io REG_Cfg9346 |
mov al, CFG_9346_Unlock |
out dx, al |
set_io REG_ChipCmd |
mov al, CMD_TxEnb or CMD_RxEnb |
out dx, al |
set_io REG_ETThReg |
mov al, ETTh |
out dx, al |
; For gigabit rtl8169 |
set_io REG_RxMaxSize |
mov ax, RxPacketMaxSize |
out dx, ax |
; Set Rx Config register |
set_io REG_RxConfig |
in ax, dx |
mov ecx, [tpc.chipset] |
and eax, [rtl_chip_info + ecx * 8 + 4] ; RxConfigMask |
or eax, rx_config |
out dx, eax |
; Set DMA burst size and Interframe Gap Time |
set_io REG_TxConfig |
mov eax, (TX_DMA_BURST shl TXC_DMAShift) or (InterFrameGap shl TXC_InterFrameGapShift) |
out dx, eax |
set_io REG_CPlusCmd |
in ax, dx |
out dx, ax |
in ax, dx |
or ax, 1 shl 3 |
cmp [tpc.mcfg], MCFG_METHOD_02 |
jne @f |
cmp [tpc.mcfg], MCFG_METHOD_03 |
jne @f |
or ax,1 shl 14 |
DEBUGF 1,"Set MAC Reg C+CR Offset 0xE0: bit-3 and bit-14\n" |
jmp .set |
@@: |
DEBUGF 1,"Set MAC Reg C+CR Offset 0xE0: bit-3\n" |
.set: |
set_io REG_CPlusCmd |
out dx, ax |
set_io 0xE2 |
; mov ax, 0x1517 |
; out dx, ax |
; mov ax, 0x152a |
; out dx, ax |
; mov ax, 0x282a |
; out dx, ax |
xor ax, ax |
out dx, ax |
xor eax, eax |
mov [tpc.cur_rx], eax |
lea eax, [device.tx_ring] |
GetRealAddr |
set_io REG_TxDescStartAddr |
out dx, eax |
lea eax, [device.rx_ring] |
GetRealAddr |
set_io REG_RxDescStartAddr |
out dx, eax |
set_io REG_Cfg9346 |
mov al, CFG_9346_Lock |
out dx, al |
udelay 10 |
xor eax, eax |
set_io REG_RxMissed |
out dx, eax |
call set_rx_mode |
set_io 0 |
; no early-rx interrupts |
set_io REG_MultiIntr |
in ax, dx |
and ax, 0xF000 |
out dx, ax |
; set interrupt mask |
set_io REG_IntrMask |
mov ax, intr_mask |
out dx, ax |
xor eax, eax |
ret |
align 4 |
read_mac: |
set_io 0 |
set_io REG_MAC0 |
xor ecx, ecx |
lea edi, [device.mac] |
mov ecx, 6 |
; Get MAC address. FIXME: read EEPROM |
@@: in al, dx |
stosb |
inc edx |
loop @r |
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
align 4 |
write_mac: |
ret 6 |
;*************************************************************************** |
; Function |
; transmit |
; Description |
; Transmits a packet of data via the ethernet card |
; |
; Destroyed registers |
; eax, edx, esi, edi |
; |
;*************************************************************************** |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], MAX_ETH_FRAME_SIZE |
ja .fail |
;---------------------------------- |
; Find currentTX descriptor address |
mov eax, tx_desc.size |
mul [tpc.cur_tx] |
lea esi, [eax + device.tx_ring] |
DEBUGF 1,"Using TX desc: %x\n", esi |
;--------------------------- |
; Program the packet pointer |
mov eax, [esp + 4] |
mov [esi + tx_desc.buf_soft_addr], eax |
GetRealAddr |
mov dword [esi + tx_desc.buf_addr], eax |
;------------------------ |
; Program the packet size |
mov eax, [esp + 8] |
@@: or eax, DSB_OWNbit or DSB_FSbit or DSB_LSbit |
cmp [tpc.cur_tx], NUM_TX_DESC - 1 |
jne @f |
or eax, DSB_EORbit |
@@: mov [esi + tx_desc.status], eax |
;----------------------------------------- |
; Set the polling bit (start transmission) |
set_io 0 |
set_io REG_TxPoll |
mov al, 0x40 ; set polling bit |
out dx, al |
;----------------------- |
; Update TX descriptor |
inc [tpc.cur_tx] |
and [tpc.cur_tx], NUM_TX_DESC - 1 |
;------------- |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp + 8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
xor eax, eax |
ret 8 |
.fail: |
DEBUGF 1,"transmit failed\n" |
or eax, -1 |
stdcall KernelFree, [esp+4] |
ret 8 |
;;;DSB_OWNbit |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io REG_IntrStatus |
in ax, dx |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, ax |
cmp ax, 0xFFFF ; if so, hardware is no longer present |
je .fail |
;-------- |
; Receive |
test ax, ISB_RxOK |
jz .no_rx |
push ax |
push ebx |
.check_more: |
pop ebx |
DEBUGF 1,"ebx = 0x%x\n", ebx |
mov eax, rx_desc.size |
mul [tpc.cur_rx] |
lea esi, [eax + device.rx_ring] |
DEBUGF 1,"RxDesc.status = 0x%x\n", [esi + rx_desc.status] |
mov eax, [esi + rx_desc.status] |
test eax, DSB_OWNbit ;;; |
jnz .rx_return |
DEBUGF 1,"tpc.cur_rx = %u\n", [tpc.cur_rx] |
test eax, SD_RxRES |
jnz .rx_return ;;;;; RX error! |
push ebx |
push .check_more |
and eax, 0x00001FFF |
add eax, -4 ; we dont need CRC |
push eax |
DEBUGF 1,"data length = %u\n", ax |
;------------- |
; Update stats |
add dword [device.bytes_rx], eax |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
push [esi + rx_desc.buf_soft_addr] |
;---------------------- |
; Allocate a new buffer |
stdcall KernelAlloc, RX_BUF_SIZE |
mov [esi + rx_desc.buf_soft_addr], eax |
GetRealAddr |
mov dword [esi + rx_desc.buf_addr], eax |
;--------------- |
; re set OWN bit |
mov eax, DSB_OWNbit or RX_BUF_SIZE |
cmp [tpc.cur_rx], NUM_RX_DESC - 1 |
jne @f |
or eax, DSB_EORbit |
@@: mov [esi + rx_desc.status], eax |
;-------------- |
; Update rx ptr |
inc [tpc.cur_rx] |
and [tpc.cur_rx], NUM_RX_DESC - 1 |
jmp Eth_input |
.rx_return: |
pop ax |
.no_rx: |
;--------- |
; Transmit |
test ax, ISB_TxOK |
jz .no_tx |
push ax |
DEBUGF 1,"TX ok!\n" |
mov ecx, NUM_TX_DESC |
lea esi, [device.tx_ring] |
.txloop: |
cmp [esi + tx_desc.buf_soft_addr], 0 |
jz .maybenext |
test [esi + tx_desc.status], DSB_OWNbit |
jnz .maybenext |
push ecx |
DEBUGF 1,"Freeing up TX desc: %x\n", esi |
stdcall KernelFree, [esi + tx_desc.buf_soft_addr] |
pop ecx |
and [esi + tx_desc.buf_soft_addr], 0 |
.maybenext: |
add esi, tx_desc.size |
dec ecx |
jnz .txloop |
pop ax |
.no_tx: |
;------- |
; Finish |
set_io 0 |
set_io REG_IntrStatus |
out dx, ax ; ACK all interrupts |
.fail: |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'RTL8169',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
rtl_chip_info dd \ |
MCFG_METHOD_01, 0xff7e1880, \ ; RTL8169 |
MCFG_METHOD_02, 0xff7e1880, \ ; RTL8169s/8110s |
MCFG_METHOD_03, 0xff7e1880, \ ; RTL8169s/8110s |
MCFG_METHOD_04, 0xff7e1880, \ ; RTL8169sb/8110sb |
MCFG_METHOD_05, 0xff7e1880, \ ; RTL8169sc/8110sc |
MCFG_METHOD_11, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E |
MCFG_METHOD_12, 0xff7e1880, \ ; RTL8168b/8111b // PCI-E |
MCFG_METHOD_13, 0xff7e1880, \ ; RTL8101e // PCI-E 8139 |
MCFG_METHOD_14, 0xff7e1880, \ ; RTL8100e // PCI-E 8139 |
MCFG_METHOD_15, 0xff7e1880 ; RTL8100e // PCI-E 8139 |
mac_info dd \ |
0x38800000, MCFG_METHOD_15, \ |
0x38000000, MCFG_METHOD_12, \ |
0x34000000, MCFG_METHOD_13, \ |
0x30800000, MCFG_METHOD_14, \ |
0x30000000, MCFG_METHOD_11, \ |
0x18000000, MCFG_METHOD_05, \ |
0x10000000, MCFG_METHOD_04, \ |
0x04000000, MCFG_METHOD_03, \ |
0x00800000, MCFG_METHOD_02, \ |
0x00000000, MCFG_METHOD_01 ; catch-all |
name_01 db "RTL8169", 0 |
name_02_03 db "RTL8169s/8110s", 0 |
name_04 db "RTL8169sb/8110sb", 0 |
name_05 db "RTL8169sc/8110sc", 0 |
name_11_12 db "RTL8168b/8111b", 0 ; PCI-E |
name_13 db "RTL8101e", 0 ; PCI-E 8139 |
name_14_15 db "RTL8100e", 0 ; PCI-E 8139 |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/bcm57xx.asm |
---|
0,0 → 1,415 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Broadcom NetXtreme 57xx driver for KolibriOS ;; |
;; ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Broadcom's programmers's manual for the BCM57xx ;; |
;; http://www.broadcom.com/collateral/pg/57XX-PG105-R.pdf ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; TODO: make better use of the available descriptors |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
virtual at ebx |
device: |
ETH_DEVICE |
.mmio_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.cur_tx dd ? |
.last_tx dd ? |
rb 0x100 - (($ - device) and 0xff) |
.rx_desc rd 256/8 |
rb 0x100 - (($ - device) and 0xff) |
.tx_desc rd 256/8 |
sizeof.device_struct = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax, [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte [device.pci_bus] |
jne .next |
cmp ah, byte [device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
.next: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte [eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte [eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base mmio addres of the PCI device |
PCI_find_mmio32 |
; Create virtual mapping of the physical memory |
push 1Bh ; PG_SW+PG_NOCACHE |
push 10000h ; size of the map |
push eax |
call MapIoMem |
mov [device.mmio_addr], eax |
; We've found the mmio address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.mmio_addr]:8 |
; Ok, the eth_device structure is ready, let's probe the device |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (device_list) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax, -1 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; |
;; probe: enables the device (if it really is I8254X) |
;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
DEBUGF 1,"Probe\n" |
PCI_make_bus_master |
; TODO: validate the device |
align 4 |
reset: |
DEBUGF 1,"Reset\n" |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
call read_mac |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
ret |
align 4 |
read_mac: |
DEBUGF 1,"Read MAC\n" |
mov esi, [device.mmio_addr] |
lea edi, [device.mac] |
movsd |
movsw |
.mac_ok: |
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp + 8], 1514 |
ja .fail |
cmp dword [esp + 8], 60 |
jb .fail |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp + 8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
ret 8 |
.fail: |
DEBUGF 1,"Send failed\n" |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
;------------------------------------------- |
; Find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
; mov edi, [device.mmio_addr] |
; mov eax, [edi + REG_ICR] |
test eax, eax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, eax |
ret |
; End of code |
section '.data' data readable writable align 16 |
align 4 |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'BCM57XX',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/dec21x4x.asm |
---|
0,0 → 1,1696 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; DEC 21x4x driver for KolibriOS ;; |
;; ;; |
;; Based on dec21140.Asm from Solar OS by ;; |
;; Eugen Brasoveanu, ;; |
;; Ontanu Bogdan Valentin ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
RX_DES_COUNT = 4 ; no of RX descriptors, must be power of 2 |
RX_BUFF_SIZE = 2048 ; size of buffer for each descriptor, must be multiple of 4 and <= 2048 TDES1_TBS1_MASK |
TX_DES_COUNT = 4 ; no of TX descriptors, must be power of 2 |
TX_BUFF_SIZE = 2048 ; size of buffer for each descriptor, used for memory allocation only |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
virtual at ebx |
device: |
ETH_DEVICE |
.rx_p_des dd ? ; descriptors ring with received packets |
.tx_p_des dd ? ; descriptors ring with 'to transmit' packets |
.tx_free_des dd ? ; Tx descriptors available |
.tx_wr_des dd ? ; Tx current descriptor to write data to |
.tx_rd_des dd ? ; Tx current descriptor to read TX completion |
.rx_crt_des dd ? ; Rx current descriptor |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.size = $ - device |
end virtual |
;------------------------------------------- |
; configuration registers |
;------------------------------------------- |
CFCS = 4 ; configuration and status register |
CSR0 = 0x00 ; Bus mode |
CSR1 = 0x08 ; Transmit Poll Command |
CSR2 = 0x10 ; Receive Poll Command |
CSR3 = 0x18 ; Receive list base address |
CSR4 = 0x20 ; Transmit list base address |
CSR5 = 0x28 ; Status |
CSR6 = 0x30 ; Operation mode |
CSR7 = 0x38 ; Interrupt enable |
CSR8 = 0x40 ; Missed frames and overflow counter |
CSR9 = 0x48 ; Boot ROM, serial ROM, and MII management |
CSR10 = 0x50 ; Boot ROM programming address |
CSR11 = 0x58 ; General-purpose timer |
CSR12 = 0x60 ; General-purpose port |
CSR13 = 0x68 |
CSR14 = 0x70 |
CSR15 = 0x78 ; Watchdog timer |
;--------bits/commands of CSR0------------------- |
CSR0_RESET = 1b |
CSR0_WIE = 1 shl 24 ; Write and Invalidate Enable |
CSR0_RLE = 1 shl 23 ; PCI Read Line Enable |
CSR0_RML = 1 shl 21 ; PCI Read Multiple |
CSR0_CACHEALIGN_NONE = 00b shl 14 |
CSR0_CACHEALIGN_32 = 01b shl 14 |
CSR0_CACHEALIGN_64 = 10b shl 14 |
CSR0_CACHEALIGN_128 = 11b shl 14 |
; using values from linux driver.. |
CSR0_DEFAULT = CSR0_WIE + CSR0_RLE + CSR0_RML + CSR0_CACHEALIGN_NONE |
;------- CSR5 -STATUS- bits -------------------------------- |
CSR5_TI = 1 shl 0 ; Transmit interupt - frame transmition completed |
CSR5_TPS = 1 shl 1 ; Transmit process stopped |
CSR5_TU = 1 shl 2 ; Transmit Buffer unavailable |
CSR5_TJT = 1 shl 3 ; Transmit Jabber Timeout (transmitter had been excessively active) |
CSR5_UNF = 1 shl 5 ; Transmit underflow - FIFO underflow |
CSR5_RI = 1 shl 6 ; Receive Interrupt |
CSR5_RU = 1 shl 7 ; Receive Buffer unavailable |
CSR5_RPS = 1 shl 8 ; Receive Process stopped |
CSR5_RWT = 1 shl 9 ; Receive Watchdow Timeout |
CSR5_ETI = 1 shl 10 ; Early transmit Interrupt |
CSR5_GTE = 1 shl 11 ; General Purpose Timer Expired |
CSR5_FBE = 1 shl 13 ; Fatal bus error |
CSR5_ERI = 1 shl 14 ; Early receive Interrupt |
CSR5_AIS = 1 shl 15 ; Abnormal interrupt summary |
CSR5_NIS = 1 shl 16 ; normal interrupt summary |
CSR5_RS_SH = 17 ; Receive process state -shift |
CSR5_RS_MASK = 111b ; -mask |
CSR5_TS_SH = 20 ; Transmit process state -shift |
CSR5_TS_MASK = 111b ; -mask |
CSR5_EB_SH = 23 ; Error bits -shift |
CSR5_EB_MASK = 111b ; Error bits -mask |
;CSR5 TS values |
CSR5_TS_STOPPED = 000b |
CSR5_TS_RUNNING_FETCHING_DESC = 001b |
CSR5_TS_RUNNING_WAITING_TX = 010b |
CSR5_TS_RUNNING_READING_BUFF = 011b |
CSR5_TS_RUNNING_SETUP_PCKT = 101b |
CSR5_TS_SUSPENDED = 110b |
CSR5_TS_RUNNING_CLOSING_DESC = 111b |
;------- CSR6 -OPERATION MODE- bits -------------------------------- |
CSR6_HP = 1 shl 0 ; Hash/Perfect Receive Filtering mode |
CSR6_SR = 1 shl 1 ; Start/Stop receive |
CSR6_HO = 1 shl 2 ; Hash only Filtering mode |
CSR6_PB = 1 shl 3 ; Pass bad frames |
CSR6_IF = 1 shl 4 ; Inverse filtering |
CSR6_SB = 1 shl 5 ; Start/Stop backoff counter |
CSR6_PR = 1 shl 6 ; Promiscuos mode -default after reset |
CSR6_PM = 1 shl 7 ; Pass all multicast |
CSR6_F = 1 shl 9 ; Full Duplex mode |
CSR6_OM_SH = 10 ; Operating Mode -shift |
CSR6_OM_MASK = 11b ; -mask |
CSR6_FC = 1 shl 12 ; Force Collision Mode |
CSR6_ST = 1 shl 13 ; Start/Stop Transmission Command |
CSR6_TR_SH = 14 ; Threshold Control -shift |
CSR6_TR_MASK = 11b ; -mask |
CSR6_CA = 1 shl 17 ; Capture Effect Enable |
CSR6_PS = 1 shl 18 ; Port select SRL / MII/SYM |
CSR6_HBD = 1 shl 19 ; Heartbeat Disable |
CSR6_SF = 1 shl 21 ; Store and Forward -transmit full packet only |
CSR6_TTM = 1 shl 22 ; Transmit Threshold Mode - |
CSR6_PCS = 1 shl 23 ; PCS active and MII/SYM port operates in symbol mode |
CSR6_SCR = 1 shl 24 ; Scrambler Mode |
CSR6_MBO = 1 shl 25 ; Must Be One |
CSR6_RA = 1 shl 30 ; Receive All |
CSR6_SC = 1 shl 31 ; Special Capture Effect Enable |
;------- CSR7 -INTERRUPT ENABLE- bits -------------------------------- |
CSR7_TI = 1 shl 0 ; transmit Interrupt Enable (set with CSR7<16> & CSR5<0> ) |
CSR7_TS = 1 shl 1 ; transmit Stopped Enable (set with CSR7<15> & CSR5<1> ) |
CSR7_TU = 1 shl 2 ; transmit buffer underrun Enable (set with CSR7<16> & CSR5<2> ) |
CSR7_TJ = 1 shl 3 ; transmit jabber timeout enable (set with CSR7<15> & CSR5<3> ) |
CSR7_UN = 1 shl 5 ; underflow Interrupt enable (set with CSR7<15> & CSR5<5> ) |
CSR7_RI = 1 shl 6 ; receive Interrupt enable (set with CSR7<16> & CSR5<5> ) |
CSR7_RU = 1 shl 7 ; receive buffer unavailable enable (set with CSR7<15> & CSR5<7> ) |
CSR7_RS = 1 shl 8 ; Receive stopped enable (set with CSR7<15> & CSR5<8> ) |
CSR7_RW = 1 shl 9 ; receive watchdog timeout enable (set with CSR7<15> & CSR5<9> ) |
CSR7_ETE = 1 shl 10 ; Early transmit Interrupt enable (set with CSR7<15> & CSR5<10> ) |
CSR7_GPT = 1 shl 11 ; general purpose timer enable (set with CSR7<15> & CSR5<11> ) |
CSR7_FBE = 1 shl 13 ; Fatal bus error enable (set with CSR7<15> & CSR5<13> ) |
CSR7_ERE = 1 shl 14 ; Early receive enable (set with CSR7<16> & CSR5<14> ) |
CSR7_AI = 1 shl 15 ; Abnormal Interrupt Summary Enable (enables CSR5<0,3,7,8,9,10,13>) |
CSR7_NI = 1 shl 16 ; Normal Interrup Enable (enables CSR5<0,2,6,11,14>) |
CSR7_DEFAULT = CSR7_TI + CSR7_TS + CSR7_RI + CSR7_RS + CSR7_TU + CSR7_TJ + CSR7_UN + \ |
CSR7_RU + CSR7_RW + CSR7_FBE + CSR7_AI + CSR7_NI |
;----------- descriptor structure --------------------- |
struc DES { |
.status dd ? ; bit 31 is 'own' and rest is 'status' |
.length dd ? ; control bits + bytes-count buffer 1 + bytes-count buffer 2 |
.buffer1 dd ? ; pointer to buffer1 |
.buffer2 dd ? ; pointer to buffer2 or in this case to next descriptor, as we use a chained structure |
.virtaddr dd ? |
.size = 64 ; 64, for alignment purposes |
} |
virtual at 0 |
DES DES |
end virtual |
;common to Rx and Tx |
DES0_OWN = 1 shl 31 ; if set, the NIC controls the descriptor, otherwise driver 'owns' the descriptors |
;receive |
RDES0_ZER = 1 shl 0 ; must be 0 if legal length :D |
RDES0_CE = 1 shl 1 ; CRC error, valid only on last desc (RDES0<8>=1) |
RDES0_DB = 1 shl 2 ; dribbling bit - not multiple of 8 bits, valid only on last desc (RDES0<8>=1) |
RDES0_RE = 1 shl 3 ; Report on MII error.. i dont realy know what this means :P |
RDES0_RW = 1 shl 4 ; received watchdog timer expiration - must set CSR5<9>, valid only on last desc (RDES0<8>=1) |
RDES0_FT = 1 shl 5 ; frame type: 0->IEEE802.0 (len<1500) 1-> ETHERNET frame (len>1500), valid only on last desc (RDES0<8>=1) |
RDES0_CS = 1 shl 6 ; Collision seen, valid only on last desc (RDES0<8>=1) |
RDES0_TL = 1 shl 7 ; Too long(>1518)-NOT AN ERROR, valid only on last desc (RDES0<8>=1) |
RDES0_LS = 1 shl 8 ; Last descriptor of current frame |
RDES0_FS = 1 shl 9 ; First descriptor of current frame |
RDES0_MF = 1 shl 10 ; Multicast frame, valid only on last desc (RDES0<8>=1) |
RDES0_RF = 1 shl 11 ; Runt frame, valid only on last desc (RDES0<8>=1) and id overflow |
RDES0_DT_SERIAL = 00b shl 12 ; Data type-Serial recv frame, valid only on last desc (RDES0<8>=1) |
RDES0_DT_INTERNAL = 01b shl 12 ; Data type-Internal loopback recv frame, valid only on last desc (RDES0<8>=1) |
RDES0_DT_EXTERNAL = 11b shl 12 ; Data type-External loopback recv frame, valid only on last desc (RDES0<8>=1) |
RDES0_DE = 1 shl 14 ; Descriptor error - cant own a new desc and frame doesnt fit, valid only on last desc (RDES0<8>=1) |
RDES0_ES = 1 shl 15 ; Error Summmary - bits 1+6+11+14, valid only on last desc (RDES0<8>=1) |
RDES0_FL_SH = 16 ; Field length shift, valid only on last desc (RDES0<8>=1) |
RDES0_FL_MASK = 11111111111111b ; Field length mask (+CRC), valid only on last desc (RDES0<8>=1) |
RDES0_FF = 1 shl 30 ; Filtering fail-frame failed address recognition test(must CSR6<30>=1), valid only on last desc (RDES0<8>=1) |
RDES1_RBS1_MASK = 11111111111b ; first buffer size MASK |
RDES1_RBS2_SH = 11 ; second buffer size SHIFT |
RDES1_RBS2_MASK = 11111111111b ; second buffer size MASK |
RDES1_RCH = 1 shl 24 ; Second address chained - second address (buffer) is next desc address |
RDES1_RER = 1 shl 25 ; Receive End of Ring - final descriptor, NIC must return to first desc |
;transmition |
TDES0_DE = 1 shl 0 ; Deffered |
TDES0_UF = 1 shl 1 ; Underflow error |
TDES0_LF = 1 shl 2 ; Link fail report (only if CSR6<23>=1) |
TDES0_CC_SH = 3 ; Collision Count shift - no of collision before transmition |
TDES0_CC_MASK = 1111b ; Collision Count mask |
TDES0_HF = 1 shl 7 ; Heartbeat fail |
TDES0_EC = 1 shl 8 ; Excessive Collisions - >16 collisions |
TDES0_LC = 1 shl 9 ; Late collision |
TDES0_NC = 1 shl 10 ; No carrier |
TDES0_LO = 1 shl 11 ; Loss of carrier |
TDES0_TO = 1 shl 14 ; Transmit Jabber Timeout |
TDES0_ES = 1 shl 15 ; Error summary TDES0<1+8+9+10+11+14>=1 |
TDES1_TBS1_MASK = 11111111111b ; Buffer 1 size mask |
TDES1_TBS2_SH = 11 ; Buffer 2 size shift |
TDES1_TBS2_MASK = 11111111111b ; Buffer 2 size mask |
TDES1_FT0 = 1 shl 22 ; Filtering type 0 |
TDES1_DPD = 1 shl 23 ; Disabled padding for packets <64bytes, no padding |
TDES1_TCH = 1 shl 24 ; Second address chained - second buffer pointer is to next desc |
TDES1_TER = 1 shl 25 ; Transmit end of ring - final descriptor |
TDES1_AC = 1 shl 26 ; Add CRC disable -pretty obvious |
TDES1_SET = 1 shl 27 ; Setup packet |
TDES1_FT1 = 1 shl 28 ; Filtering type 1 |
TDES1_FS = 1 shl 29 ; First segment - buffer is first segment of frame |
TDES1_LS = 1 shl 30 ; Last segment |
TDES1_IC = 1 shl 31 ; Interupt on completion (CSR5<0>=1) valid when TDES1<30>=1 |
MAX_ETH_FRAME_SIZE = 1514 |
RX_MEM_TOTAL_SIZE = RX_DES_COUNT*(DES.size+RX_BUFF_SIZE) |
TX_MEM_TOTAL_SIZE = TX_DES_COUNT*(DES.size+TX_BUFF_SIZE) |
;============================================================================= |
; serial ROM operations |
;============================================================================= |
CSR9_SR = 1 shl 11 ; SROM Select |
CSR9_RD = 1 shl 14 ; ROM Read Operation |
CSR9_SROM_DO = 1 shl 3 ; Data Out for SROM |
CSR9_SROM_DI = 1 shl 2 ; Data In to SROM |
CSR9_SROM_CK = 1 shl 1 ; clock for SROM |
CSR9_SROM_CS = 1 shl 0 ; chip select.. always needed |
; assume dx is CSR9 |
macro SROM_Delay { |
push eax |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
pop eax |
} |
; assume dx is CSR9 |
macro MDIO_Delay { |
push eax |
in eax, dx |
pop eax |
} |
macro Bit_Set a_bit { |
in eax, dx |
or eax, a_bit |
out dx , eax |
} |
macro Bit_Clear a_bit { |
in eax, dx |
and eax, not (a_bit) |
out dx, eax |
} |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
push edx |
stdcall KernelAlloc, dword device.size ; Allocate the buffer for eth_device structure |
pop edx |
test eax, eax |
jz .fail |
mov ebx, eax ; ebx is always used as a pointer to the structure (in driver, but also in kernel code) |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 |
allocate_and_clear [device.rx_p_des], RX_DES_COUNT*(DES.size+RX_BUFF_SIZE), .err |
allocate_and_clear [device.tx_p_des], TX_DES_COUNT*(DES.size+TX_BUFF_SIZE), .err |
; Ok, the eth_device structure is ready, let's probe the device |
; Because initialization fires IRQ, IRQ handler must be aware of this device |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
call probe ; this function will output in eax |
test eax, eax |
jnz .err2 ; If an error occured, exit |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 2,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err2: |
dec [devices] |
.err: |
DEBUGF 2,"removing device structure\n" |
stdcall KernelFree, [device.rx_p_des] |
stdcall KernelFree, [device.tx_p_des] |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (RTL8139_LIST) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
macro status { |
set_io CSR5 |
in eax, dx |
DEBUGF 1,"CSR5: %x\n", eax |
} |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Probe ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
probe: |
DEBUGF 2,"Probing dec21x4x device: " |
PCI_make_bus_master |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 ; get device/vendor id |
DEBUGF 1,"Vendor id: 0x%x\n", ax |
cmp ax, 0x1011 |
je .dec |
cmp ax, 0x1317 |
je .admtek |
jmp .notfound |
.dec: |
shr eax, 16 |
DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax ; TODO: use another method to detect chip! |
cmp ax, 0x0009 |
je .supported_device |
cmp ax, 0x0019 |
je .supported_device2 |
.admtek: |
shr eax, 16 |
DEBUGF 1,"Vendor ok!, device id: 0x%x\n", ax |
cmp ax, 0x0985 |
je .supported_device |
.notfound: |
DEBUGF 1,"Device not supported!\n" |
or eax, -1 |
ret |
.supported_device2: |
; wake up the 21143 |
xor eax, eax |
stdcall PciWrite32, [device.pci_bus], [device.pci_dev], 0x40, eax |
.supported_device: |
call SROM_GetWidth ; TODO: use this value returned in ecx |
; in the read_word routine! |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Reset ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
reset: |
DEBUGF 2,"Resetting dec21x4x\n" |
;----------------------------------------------------------- |
; board software reset - if fails, dont do nothing else |
set_io 0 |
status |
set_io CSR0 |
mov eax, CSR0_RESET |
out dx, eax |
; wait at least 50 PCI cycles |
mov esi, 1000 |
call Sleep |
;----------- |
; setup CSR0 |
set_io 0 |
status |
set_io CSR0 |
mov eax, CSR0_DEFAULT |
out dx, eax |
; wait at least 50 PCI cycles |
mov esi, 1000 |
call Sleep |
;----------------------------------- |
; Read mac from eeprom to driver ram |
call read_mac_eeprom |
;-------------------------------- |
; insert irq handler on given irq |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
set_io 0 |
status |
call init_ring |
;-------------------------------------------- |
; setup CSR3 & CSR4 (pointers to descriptors) |
set_io 0 |
status |
set_io CSR3 |
mov eax, [device.rx_p_des] |
GetRealAddr |
DEBUGF 1,"RX descriptor base address: %x\n", eax |
out dx, eax |
set_io CSR4 |
mov eax, [device.tx_p_des] |
GetRealAddr |
DEBUGF 1,"TX descriptor base address: %x\n", eax |
out dx, eax |
;------------------------------------------------------- |
; setup interrupt mask register -expect IRQs from now on |
status |
DEBUGF 1,"Enabling interrupts\n" |
set_io CSR7 |
mov eax, CSR7_DEFAULT |
out dx, eax |
status |
;---------- |
; enable RX |
set_io 0 |
status |
DEBUGF 1,"Enable RX\n" |
set_io CSR6 |
Bit_Set CSR6_SR; or CSR6_PR or CSR6_ST |
DEBUGF 1,"CSR6: %x\n", eax |
status |
call start_link |
; wait a bit |
mov esi, 3000 |
call Sleep |
;---------------------------------------------------- |
; send setup packet to notify the board about the MAC |
call Send_Setup_Packet |
xor eax, eax |
; clear packet/byte counters |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
DEBUGF 1,"Reset done\n" |
ret |
align 4 |
init_ring: |
;------------------------------------------ |
; Setup RX descriptors (use chained method) |
mov eax, [device.rx_p_des] |
GetRealAddr |
mov edx, eax |
push eax |
lea esi, [eax + RX_DES_COUNT*(DES.size)] ; jump over RX descriptors |
mov eax, [device.rx_p_des] |
add eax, RX_DES_COUNT*(DES.size) ; jump over RX descriptors |
mov edi, [device.rx_p_des] |
mov ecx, RX_DES_COUNT |
.loop_rx_des: |
add edx, DES.size |
mov [edi + DES.status], DES0_OWN ; hardware owns buffer |
mov [edi + DES.length], 1984 + RDES1_RCH ; only size of first buffer, chained buffers |
mov [edi + DES.buffer1], esi ; hw buffer address |
mov [edi + DES.buffer2], edx ; pointer to next descriptor |
mov [edi + DES.virtaddr], eax ; virtual buffer address |
DEBUGF 1,"RX desc: buff addr: %x, next desc: %x, real buff addr: %x, real descr addr: %x \n", esi, edx, eax, edi |
add esi, RX_BUFF_SIZE |
add eax, RX_BUFF_SIZE |
add edi, DES.size |
dec ecx |
jnz .loop_rx_des |
; set last descriptor as LAST |
sub edi, DES.size |
or [edi + DES.length], RDES1_RER ; EndOfRing |
pop [edi + DES.buffer2] ; point it to the first descriptor |
;--------------------- |
; Setup TX descriptors |
mov eax, [device.tx_p_des] |
GetRealAddr |
mov edx, eax |
push eax |
lea esi, [eax + TX_DES_COUNT*(DES.size)] ; jump over TX descriptors |
mov eax, [device.tx_p_des] |
add eax, TX_DES_COUNT*(DES.size) ; jump over TX descriptors |
mov edi, [device.tx_p_des] |
mov ecx, TX_DES_COUNT |
.loop_tx_des: |
add edx, DES.size |
mov [edi + DES.status], 0 ; owned by driver |
mov [edi + DES.length], TDES1_TCH ; chained method |
mov [edi + DES.buffer1], esi ; pointer to buffer |
mov [edi + DES.buffer2], edx ; pointer to next descr |
mov [edi + DES.virtaddr], eax |
DEBUGF 1,"TX desc: buff addr: %x, next desc: %x, virt buff addr: %x, virt descr addr: %x \n", esi, edx, eax, edi |
add esi, TX_BUFF_SIZE |
add eax, TX_BUFF_SIZE |
add edi, DES.size |
dec ecx |
jnz .loop_tx_des |
; set last descriptor as LAST |
sub edi, DES.size |
or [edi + DES.length], TDES1_TER ; EndOfRing |
pop [edi + DES.buffer2] ; point it to the first descriptor |
;------------------ |
; Reset descriptors |
mov [device.tx_wr_des], 0 |
mov [device.tx_rd_des], 0 |
mov [device.rx_crt_des], 0 |
mov [device.tx_free_des], TX_DES_COUNT |
ret |
align 4 |
start_link: |
; TODO: write working code here |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Send setup packet ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
Send_Setup_Packet: |
DEBUGF 1,"Sending setup packet\n" |
; if no descriptors available, out |
mov ecx, 1000 |
@@loop_wait_desc: |
cmp [device.tx_free_des], 0 |
jne @f |
dec ecx |
jnz @@loop_wait_desc |
mov eax, -1 |
ret |
@@: |
; go to current send descriptor |
mov edi, [device.tx_p_des] |
mov eax, [device.tx_wr_des] |
DEBUGF 1,"Got free descriptor: %u (%x)", eax, edi |
mov edx, DES.size |
mul edx |
add edi, eax |
DEBUGF 1,"=>%x\n", edi |
; if NOT sending FIRST setup packet, must set current descriptor to 0 size for both buffers, |
; and go to next descriptor for real setup packet... ;; TODO: check if 2 descriptors are available |
; cmp [device.tx_packets], 0 |
; je .first |
; |
; and [edi+DES.des1], 0 |
; mov [edi+DES.des0], DES0_OWN |
; |
; go to next descriptor |
; inc [device.tx_wr_des] |
; and [device.tx_wr_des], TX_DES_COUNT-1 |
; |
; dec free descriptors count |
; cmp [device.tx_free_des], 0 |
; jz @f |
; dec [device.tx_free_des] |
; @@: |
; |
; ; recompute pointer to current descriptor |
; mov edi, [device.tx_p_des] |
; mov eax, [device.tx_wr_des] |
; mov edx, DES.size |
; mul edx |
; add edi, eax |
.first: |
push edi |
; copy setup packet to current descriptor |
mov edi, [edi + DES.virtaddr] |
; copy the address once |
lea esi, [device.mac] |
DEBUGF 1,"copying packet to %x from %x\n", edi, esi |
mov ecx, 3 ; mac is 6 bytes thus 3 words |
.loop: |
DEBUGF 1,"%x ", [esi]:4 |
movsw |
inc edi |
inc edi |
dec ecx |
jnz .loop |
DEBUGF 1,"\n" |
; copy 15 times the broadcast address |
mov ecx, 3*15 |
mov eax, 0xffffffff |
rep stosd |
pop edi |
; setup descriptor |
DEBUGF 1,"setting up descriptor\n" |
mov [edi + DES.length], TDES1_IC + TDES1_SET + TDES1_TCH + 192 ; size must be EXACTLY 192 bytes |
mov [edi + DES.status], DES0_OWN |
DEBUGF 1,"status: %x\n", [edi + DES.status]:8 |
DEBUGF 1,"length: %x\n", [edi + DES.length]:8 |
DEBUGF 1,"buffer1: %x\n", [edi + DES.buffer1]:8 |
DEBUGF 1,"buffer2: %x\n", [edi + DES.buffer2]:8 |
; go to next descriptor |
inc [device.tx_wr_des] |
and [device.tx_wr_des], TX_DES_COUNT-1 |
; dec free descriptors count |
cmp [device.tx_free_des], 0 |
jz @f |
dec [device.tx_free_des] |
@@: |
; start tx |
set_io 0 |
status |
set_io CSR6 |
in eax, dx |
test eax, CSR6_ST ; if NOT started, start now |
jnz .already_started |
or eax, CSR6_ST |
DEBUGF 1,"Starting TX\n" |
jmp .do_it |
.already_started: |
; if already started, issue a Transmit Poll command |
set_io CSR1 |
xor eax, eax |
DEBUGF 1,"Issuing transmit poll command\n" |
.do_it: |
out dx, eax |
status |
DEBUGF 1,"Sending setup packet, completed!\n" |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], MAX_ETH_FRAME_SIZE |
ja .fail |
cmp [device.tx_free_des], 0 |
je .fail |
;-------------------------- |
; copy packet to crt buffer |
mov eax, [device.tx_wr_des] |
mov edx, DES.size |
mul edx |
add eax, [device.tx_p_des] |
mov edi, [eax + DES.virtaddr] ; pointer to buffer |
mov esi, [esp+4] |
mov ecx, [esp+8] |
DEBUGF 1,"copying %u bytes from %x to %x\n", ecx, esi, edi |
rep movsb |
; set packet size |
mov ecx, [eax+DES.length] |
and ecx, TDES1_TER ; preserve 'End of Ring' bit |
or ecx, [esp+8] ; set size |
or ecx, TDES1_FS or TDES1_LS or TDES1_IC or TDES1_TCH ; first descr, last descr, interrupt on complete, chained modus |
mov [eax+DES.length], ecx |
; set descriptor info |
mov [eax+DES.status], DES0_OWN ; say it is now owned by the 21x4x |
; start tx |
set_io 0 |
status |
set_io CSR6 |
in eax, dx |
test eax, CSR6_ST ; if NOT started, start now |
jnz .already_started |
or eax, CSR6_ST |
DEBUGF 1,"Starting TX\n" |
jmp .do_it |
.already_started: |
; if already started, issues a Transmit Poll command |
set_io CSR1 |
mov eax, -1 |
.do_it: |
out dx , eax |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
; go to next descriptor |
inc [device.tx_wr_des] |
and [device.tx_wr_des], TX_DES_COUNT-1 |
; dec free descriptors count |
test [device.tx_free_des], -1 |
jz .end |
dec [device.tx_free_des] |
.end: |
status |
DEBUGF 1,"transmit ok\n" |
xor eax, eax |
stdcall KernelFree, [esp+4] |
ret 8 |
.fail: |
DEBUGF 1,"transmit failed\n" |
or eax, -1 |
stdcall KernelFree, [esp+4] |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io CSR5 |
in eax, dx |
out dx, eax ; send it back to ACK |
test eax, eax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1,"Device: %x CSR5: %x ", ebx, ax |
;---------------------------------- |
; TX ok? |
test ax, CSR5_TI |
jz .not_tx |
push ax esi ecx |
DEBUGF 1,"TX ok!\n" |
; go to current descriptor |
mov edi, [device.tx_p_des] |
mov eax, [device.tx_rd_des] |
mov edx, DES.size |
mul edx |
add edi, eax |
.loop_tx: |
; done if all desc are free |
cmp [device.tx_free_des], TX_DES_COUNT |
jz .end_tx |
mov eax, [edi+DES.status] |
; we stop at first desc that is owned be NIC |
test eax, DES0_OWN |
jnz .end_tx |
; detect is setup packet |
cmp eax, (0ffffffffh - DES0_OWN) ; all other bits are 1 |
jne .not_setup_packet |
DEBUGF 1,"Setup Packet detected\n" |
.not_setup_packet: |
DEBUGF 1,"packet status: %x\n", eax |
; next descriptor |
add edi, DES.size |
inc [device.tx_rd_des] |
and [device.tx_rd_des], TX_DES_COUNT-1 |
; inc free desc |
inc [device.tx_free_des] |
cmp [device.tx_free_des], TX_DES_COUNT |
jbe @f |
mov [device.tx_free_des], TX_DES_COUNT |
@@: |
jmp .loop_tx |
.end_tx: |
;------------------------------------------------------ |
; here must be called standard Ethernet Tx Irq Handler |
;------------------------------------------------------ |
pop ecx esi ax |
;---------------------------------- |
; RX irq |
.not_tx: |
test ax, CSR5_RI |
jz .not_rx |
push ax esi ecx |
DEBUGF 1,"RX ok!\n" |
push ebx |
.rx_loop: |
pop ebx |
; get current descriptor |
mov edi, [device.rx_p_des] |
mov eax, [device.rx_crt_des] |
mov edx, DES.size |
mul edx |
add edi, eax |
; now check status |
mov eax, [edi + DES.status] |
test eax, DES0_OWN |
jnz .end_rx ; current desc is busy, nothing to do |
test eax, RDES0_FS |
jz .end_rx ; current desc is NOT first packet, ERROR! |
test eax, RDES0_LS ; if not last desc of packet, error for now |
jz .end_rx |
test eax, RDES0_ES |
jnz .end_rx |
mov esi, [edi + DES.virtaddr] |
mov ecx, [edi + DES.status] |
shr ecx, RDES0_FL_SH |
and ecx, RDES0_FL_MASK |
sub ecx, 4 ; crc, we dont need it |
DEBUGF 1,"Received packet!, size=%u, addr:%x\n", ecx, esi |
push esi edi ecx |
stdcall KernelAlloc, ecx ; Allocate a buffer to put packet into |
pop ecx edi esi |
test eax, eax |
jz .fail |
push ebx |
push dword .rx_loop |
push ecx eax |
mov edi, eax |
; update statistics |
inc [device.packets_rx] |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
; copy packet data |
shr cx , 1 |
jnc .nb |
movsb |
.nb: |
shr cx , 1 |
jnc .nw |
movsw |
.nw: |
rep movsd |
mov [edi + DES.status], DES0_OWN ; free descriptor |
inc [device.rx_crt_des] ; next descriptor |
and [device.rx_crt_des], RX_DES_COUNT-1 |
jmp Eth_input |
.end_rx: |
.fail: |
pop ecx esi ax |
.not_rx: |
jmp .continue |
align 4 |
write_mac: ; in: mac pushed onto stack (as 3 words) |
DEBUGF 2,"Writing MAC: " |
; write data into driver cache |
mov esi, esp |
lea edi, [device.mac] |
movsd |
movsw |
add esp, 6 |
; send setup packet (only if driver is started) |
call Send_Setup_Packet |
align 4 |
read_mac: |
DEBUGF 1,"Read_mac\n" |
ret |
align 4 |
read_mac_eeprom: |
DEBUGF 1,"Read_mac_eeprom\n" |
lea edi, [device.mac] |
mov esi, 20/2 ; read words, start address is 20 |
.loop: |
push esi edi |
call SROM_Read_Word |
pop edi esi |
stosw |
inc esi |
cmp esi, 26/2 |
jb .loop |
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[edi-6]:2,[edi-5]:2,[edi-4]:2,[edi-3]:2,[edi-2]:2,[edi-1]:2 |
ret |
align 4 |
write_mac_eeprom: |
DEBUGF 1,"Write_mac_eeprom\n" |
ret |
align 4 |
SROM_GetWidth: ; should be 6 or 8 according to some manuals (returns in ecx) |
DEBUGF 1,"SROM_GetWidth\n" |
call SROM_Idle |
call SROM_EnterAccessMode |
; set_io 0 |
; set_io CSR9 |
; send 110b |
in eax, dx |
or eax, CSR9_SROM_DI |
call SROM_out |
in eax, dx |
or eax, CSR9_SROM_DI |
call SROM_out |
in eax, dx |
and eax, not (CSR9_SROM_DI) |
call SROM_out |
mov ecx,1 |
.loop2: |
Bit_Set CSR9_SROM_CK |
SROM_Delay |
in eax, dx |
and eax, CSR9_SROM_DO |
jnz .not_zero |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
jmp .end_loop2 |
.not_zero: |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
inc ecx |
cmp ecx, 12 |
jbe .loop2 |
.end_loop2: |
DEBUGF 1,"Srom width=%u\n", ecx |
call SROM_Idle |
call SROM_EnterAccessMode |
call SROM_Idle |
ret |
align 4 |
SROM_out: |
out dx, eax |
SROM_Delay |
Bit_Set CSR9_SROM_CK |
SROM_Delay |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
ret |
align 4 |
SROM_EnterAccessMode: |
DEBUGF 1,"SROM_EnterAccessMode\n" |
set_io 0 |
set_io CSR9 |
mov eax, CSR9_SR |
out dx, eax |
SROM_Delay |
Bit_Set CSR9_RD |
SROM_Delay |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
Bit_Set CSR9_SROM_CS |
SROM_Delay |
ret |
align 4 |
SROM_Idle: |
DEBUGF 1,"SROM_Idle\n" |
call SROM_EnterAccessMode |
; set_io 0 |
; set_io CSR9 |
mov ecx, 25 |
.loop_clk: |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
Bit_Set CSR9_SROM_CK |
SROM_Delay |
dec ecx |
jnz .loop_clk |
Bit_Clear CSR9_SROM_CK |
SROM_Delay |
Bit_Clear CSR9_SROM_CS |
SROM_Delay |
xor eax, eax |
out dx, eax |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Read serial EEprom word ;; |
;; ;; |
;; In: esi = read address ;; |
;; OUT: ax = data word ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
SROM_Read_Word: |
DEBUGF 1,"SROM_Read_word at: %x result: ", esi |
set_io 0 |
set_io CSR9 |
; enter access mode |
mov eax, CSR9_SR + CSR9_RD |
out dx , eax |
or eax, CSR9_SROM_CS |
out dx , eax |
; TODO: change this hard-coded 6-bit stuff to use value from srom_getwidth |
; send read command "110b" + address to read from |
and esi, 111111b |
or esi, 110b shl 6 |
mov ecx, 1 shl 9 |
.loop_cmd: |
mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS |
test esi, ecx |
jz @f |
or eax, CSR9_SROM_DI |
@@: |
out dx , eax |
SROM_Delay |
or eax, CSR9_SROM_CK |
out dx , eax |
SROM_Delay |
shr ecx, 1 |
jnz .loop_cmd |
; read data from SROM |
xor esi, esi |
mov ecx, 17 ;;; TODO: figure out why 17, not 16 |
.loop_read: |
mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS + CSR9_SROM_CK |
out dx , eax |
SROM_Delay |
in eax, dx |
and eax, CSR9_SROM_DO |
shr eax, 3 |
shl esi, 1 |
or esi, eax |
mov eax, CSR9_SR + CSR9_RD + CSR9_SROM_CS |
out dx , eax |
SROM_Delay |
dec ecx |
jnz .loop_read |
mov eax, esi |
DEBUGF 1,"%x\n", ax |
ret |
;<<<<<<<<<<<<<<<<<<<<<<<<<<<< |
;********************************************************************* |
;* Media Descriptor Code * |
;********************************************************************* |
; MII transceiver control section. |
; Read and write the MII registers using software-generated serial |
; MDIO protocol. See the MII specifications or DP83840A data sheet |
; for details. |
; The maximum data clock rate is 2.5 Mhz. The minimum timing is usually |
; met by back-to-back PCI I/O cycles, but we insert a delay to avoid |
; "overclocking" issues or future 66Mhz PCI. |
; Read and write the MII registers using software-generated serial |
; MDIO protocol. It is just different enough from the EEPROM protocol |
; to not share code. The maxium data clock rate is 2.5 Mhz. |
MDIO_SHIFT_CLK = 0x10000 |
MDIO_DATA_WRITE0 = 0x00000 |
MDIO_DATA_WRITE1 = 0x20000 |
MDIO_ENB = 0x00000 ; Ignore the 0x02000 databook setting. |
MDIO_ENB_IN = 0x40000 |
MDIO_DATA_READ = 0x80000 |
; MII transceiver control section. |
; Read and write the MII registers using software-generated serial |
; MDIO protocol. See the MII specifications or DP83840A data sheet |
; for details. |
align 4 |
mdio_read: ; phy_id:edx, location:esi |
DEBUGF 1,"mdio read, phy=%x, location=%x", edx, esi |
shl edx, 5 |
or esi, edx |
or esi, 0xf6 shl 10 |
set_io 0 |
set_io CSR9 |
; if (tp->chip_id == LC82C168) { |
; int i = 1000; |
; outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0); |
; inl(ioaddr + 0xA0); |
; inl(ioaddr + 0xA0); |
; while (--i > 0) |
; if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000)) |
; return retval & 0xffff; |
; return 0xffff; |
; } |
; |
; if (tp->chip_id == COMET) { |
; if (phy_id == 1) { |
; if (location < 7) |
; return inl(ioaddr + 0xB4 + (location<<2)); |
; else if (location == 17) |
; return inl(ioaddr + 0xD0); |
; else if (location >= 29 && location <= 31) |
; return inl(ioaddr + 0xD4 + ((location-29)<<2)); |
; } |
; return 0xffff; |
; } |
; Establish sync by sending at least 32 logic ones. |
mov ecx, 32 |
.loop: |
mov eax, MDIO_ENB or MDIO_DATA_WRITE1 |
out dx, eax |
MDIO_Delay |
or eax, MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
dec ecx |
jnz .loop |
; Shift the read command bits out. |
mov ecx, 1 shl 15 |
.loop2: |
mov eax, MDIO_ENB |
test esi, ecx |
jz @f |
or eax, MDIO_DATA_WRITE1 |
@@: |
out dx, eax |
MDIO_Delay |
or eax, MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
shr ecx, 1 |
jnz .loop2 |
; Read the two transition, 16 data, and wire-idle bits. |
xor esi, esi |
mov ecx, 19 |
.loop3: |
mov eax, MDIO_ENB_IN |
out dx, eax |
MDIO_Delay |
shl esi, 1 |
in eax, dx |
test eax, MDIO_DATA_READ |
jz @f |
inc esi |
@@: |
mov eax, MDIO_ENB_IN or MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
dec ecx |
jnz .loop3 |
shr esi, 1 |
movzx eax, si |
DEBUGF 1,", data=%x\n", ax |
ret |
align 4 |
mdio_write: ;int phy_id: edx, int location: edi, int value: ax) |
DEBUGF 1,"mdio write, phy=%x, location=%x, data=%x\n", edx, edi, ax |
shl edi, 18 |
or edi, 0x5002 shl 16 |
shl edx, 23 |
or edi, edx |
mov di, ax |
set_io 0 |
set_io CSR9 |
; if (tp->chip_id == LC82C168) { |
; int i = 1000; |
; outl(cmd, ioaddr + 0xA0); |
; do |
; if ( ! (inl(ioaddr + 0xA0) & 0x80000000)) |
; break; |
; while (--i > 0); |
; return; |
; } |
; if (tp->chip_id == COMET) { |
; if (phy_id != 1) |
; return; |
; if (location < 7) |
; outl(value, ioaddr + 0xB4 + (location<<2)); |
; else if (location == 17) |
; outl(value, ioaddr + 0xD0); |
; else if (location >= 29 && location <= 31) |
; outl(value, ioaddr + 0xD4 + ((location-29)<<2)); |
; return; |
; } |
; Establish sync by sending at least 32 logic ones. |
mov ecx, 32 |
.loop: |
mov eax, MDIO_ENB or MDIO_DATA_WRITE1 |
out dx, eax |
MDIO_Delay |
or eax, MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
dec ecx |
jnz .loop |
; Shift the command bits out. |
mov ecx, 1 shl 31 |
.loop2: |
mov eax, MDIO_ENB |
test edi, ecx |
jz @f |
or eax, MDIO_DATA_WRITE1 |
@@: |
out dx, eax |
MDIO_Delay |
or eax, MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
shr ecx, 1 |
jnz .loop2 |
; Clear out extra bits. |
mov ecx, 2 |
.loop3: |
mov eax, MDIO_ENB |
out dx, eax |
MDIO_Delay |
or eax, MDIO_SHIFT_CLK |
out dx, eax |
MDIO_Delay |
dec ecx |
jnz .loop3 |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'DEC21X4X',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/forcedeth.asm |
---|
0,0 → 1,1981 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; FORCEDETH.INC ;; |
;; ;; |
;; Ethernet driver for Kolibri OS ;; |
;; ;; |
;; Driver for chips of NVIDIA nForce2 ;; |
;; References: ;; |
;; forcedeth.c - linux driver (etherboot project) ;; |
;; ethernet driver template by Mike Hibbett ;; |
;; ;; |
;; The copyright statement is ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Copyright 2008 shurf, ;; |
;; cit.utc@gmail.com ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
RBLEN = 0 ; Receive buffer size: 0=4K 1=8k 2=16k 3=32k 4=64k |
; FIXME: option 1 and 2 will not allocate buffer correctly causing data loss! |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
RX_RING = 4 |
TX_RING = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include '../struct.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
;************************************************************************** |
; forcedeth Register Definitions |
;************************************************************************** |
PCI_DEVICE_ID_NVIDIA_NVENET_1 = 0x01c3 |
PCI_DEVICE_ID_NVIDIA_NVENET_2 = 0x0066 |
PCI_DEVICE_ID_NVIDIA_NVENET_4 = 0x0086 |
PCI_DEVICE_ID_NVIDIA_NVENET_5 = 0x008c |
PCI_DEVICE_ID_NVIDIA_NVENET_3 = 0x00d6 |
PCI_DEVICE_ID_NVIDIA_NVENET_7 = 0x00df |
PCI_DEVICE_ID_NVIDIA_NVENET_6 = 0x00e6 |
PCI_DEVICE_ID_NVIDIA_NVENET_8 = 0x0056 |
PCI_DEVICE_ID_NVIDIA_NVENET_9 = 0x0057 |
PCI_DEVICE_ID_NVIDIA_NVENET_10 = 0x0037 |
PCI_DEVICE_ID_NVIDIA_NVENET_11 = 0x0038 |
PCI_DEVICE_ID_NVIDIA_NVENET_12 = 0x0268 |
PCI_DEVICE_ID_NVIDIA_NVENET_13 = 0x0269 |
PCI_DEVICE_ID_NVIDIA_NVENET_14 = 0x0372 |
PCI_DEVICE_ID_NVIDIA_NVENET_15 = 0x0373 |
UNKSETUP1_VAL = 0x16070f |
UNKSETUP2_VAL = 0x16 |
UNKSETUP3_VAL1 = 0x200010 |
UNKSETUP4_VAL = 8 |
UNKSETUP5_BIT31 = (1 shl 31) |
UNKSETUP6_VAL = 3 |
TXRXCTL_RXCHECK = 0x0400 |
MIISTAT_ERROR = 0x0001 |
MIISTAT_MASK = 0x000f |
MIISTAT_MASK2 = 0x000f |
MIICTL_INUSE = 0x08000 |
MIICTL_WRITE = 0x00400 |
MIICTL_ADDRSHIFT = 5 |
MIISPEED_BIT8 = (1 shl 8) |
MIIDELAY = 5 |
IRQ_RX_ERROR = 0x0001 |
IRQ_RX = 0x0002 |
IRQ_RX_NOBUF = 0x0004 |
IRQ_LINK = 0x0040 |
IRQ_TIMER = 0x0020 |
IRQMASK_WANTED_2 = 0x0147 |
IRQ_RX_ALL = IRQ_RX_ERROR or IRQ_RX or IRQ_RX_NOBUF |
IRQ_TX_ALL = 0 ; ??????????? |
IRQ_OTHER_ALL = IRQ_LINK ;or IRQ_TIMER |
IRQSTAT_MASK = 0x1ff |
TXRXCTL_KICK = 0x0001 |
TXRXCTL_BIT1 = 0x0002 |
TXRXCTL_BIT2 = 0x0004 |
TXRXCTL_IDLE = 0x0008 |
TXRXCTL_RESET = 0x0010 |
TXRXCTL_RXCHECK = 0x0400 |
MCASTADDRA_FORCE = 0x01 |
MAC_RESET_ASSERT = 0x0F3 |
MISC1_HD = 0x02 |
MISC1_FORCE = 0x3b0f3c |
PFF_ALWAYS = 0x7F0008 |
PFF_PROMISC = 0x80 |
PFF_MYADDR = 0x20 |
OFFLOAD_HOMEPHY = 0x601 |
OFFLOAD_NORMAL = 4096 shl RBLEN |
RNDSEED_MASK = 0x00ff |
RNDSEED_FORCE = 0x7f00 |
RNDSEED_FORCE2 = 0x2d00 |
RNDSEED_FORCE3 = 0x7400 |
; POLL_DEFAULT is the interval length of the timer source on the nic |
; POLL_DEFAULT=97 would result in an interval length of 1 ms |
POLL_DEFAULT = 970 |
ADAPTCTL_START = 0x02 |
ADAPTCTL_LINKUP = 0x04 |
ADAPTCTL_PHYVALID = 0x40000 |
ADAPTCTL_RUNNING = 0x100000 |
ADAPTCTL_PHYSHIFT = 24 |
WAKEUPFLAGS_VAL = 0x7770 |
POWERSTATE_POWEREDUP = 0x8000 |
POWERSTATE_VALID = 0x0100 |
POWERSTATE_MASK = 0x0003 |
POWERSTATE_D0 = 0x0000 |
POWERSTATE_D1 = 0x0001 |
POWERSTATE_D2 = 0x0002 |
POWERSTATE_D3 = 0x0003 |
POWERSTATE2_POWERUP_MASK = 0x0F11 |
POWERSTATE2_POWERUP_REV_A3= 0x0001 |
RCVCTL_START = 0x01 |
RCVSTAT_BUSY = 0x01 |
XMITCTL_START = 0x01 |
LINKSPEED_FORCE = 0x10000 |
LINKSPEED_10 = 1000 |
LINKSPEED_100 = 100 |
LINKSPEED_1000 = 50 |
RINGSZ_TXSHIFT = 0 |
RINGSZ_RXSHIFT = 16 |
LPA_1000FULL = 0x0800 |
; Link partner ability register. |
LPA_SLCT = 0x001f ; Same as advertise selector |
LPA_10HALF = 0x0020 ; Can do 10mbps half-duplex |
LPA_10FULL = 0x0040 ; Can do 10mbps full-duplex |
LPA_100HALF = 0x0080 ; Can do 100mbps half-duplex |
LPA_100FULL = 0x0100 ; Can do 100mbps full-duplex |
LPA_100BASE4 = 0x0200 ; Can do 100mbps 4k packets |
LPA_RESV = 0x1c00 ; Unused... |
LPA_RFAULT = 0x2000 ; Link partner faulted |
LPA_LPACK = 0x4000 ; Link partner acked us |
LPA_NPAGE = 0x8000 ; Next page bit |
MII_READ = (-1) |
MII_PHYSID1 = 0x02 ; PHYS ID 1 |
MII_PHYSID2 = 0x03 ; PHYS ID 2 |
MII_BMCR = 0x00 ; Basic mode control register |
MII_BMSR = 0x01 ; Basic mode status register |
MII_ADVERTISE = 0x04 ; Advertisement control reg |
MII_LPA = 0x05 ; Link partner ability reg |
MII_SREVISION = 0x16 ; Silicon revision |
MII_RESV1 = 0x17 ; Reserved... |
MII_NCONFIG = 0x1c ; Network interface config |
; PHY defines |
PHY_OUI_MARVELL = 0x5043 |
PHY_OUI_CICADA = 0x03f1 |
PHYID1_OUI_MASK = 0x03ff |
PHYID1_OUI_SHFT = 6 |
PHYID2_OUI_MASK = 0xfc00 |
PHYID2_OUI_SHFT = 10 |
PHY_INIT1 = 0x0f000 |
PHY_INIT2 = 0x0e00 |
PHY_INIT3 = 0x01000 |
PHY_INIT4 = 0x0200 |
PHY_INIT5 = 0x0004 |
PHY_INIT6 = 0x02000 |
PHY_GIGABIT = 0x0100 |
PHY_TIMEOUT = 0x1 |
PHY_ERROR = 0x2 |
PHY_100 = 0x1 |
PHY_1000 = 0x2 |
PHY_HALF = 0x100 |
PHY_RGMII = 0x10000000 |
; desc_ver values: |
; This field has two purposes: |
; - Newer nics uses a different ring layout. The layout is selected by |
; comparing np->desc_ver with DESC_VER_xy. |
; - It contains bits that are forced on when writing to TxRxControl. |
DESC_VER_1 = 0x0 |
DESC_VER_2 = (0x02100 or TXRXCTL_RXCHECK) |
MAC_ADDR_LEN = 6 |
NV_TX_LASTPACKET = (1 shl 16) |
NV_TX_RETRYERROR = (1 shl 19) |
NV_TX_LASTPACKET1 = (1 shl 24) |
NV_TX_DEFERRED = (1 shl 26) |
NV_TX_CARRIERLOST = (1 shl 27) |
NV_TX_LATECOLLISION = (1 shl 28) |
NV_TX_UNDERFLOW = (1 shl 29) |
NV_TX_ERROR = (1 shl 30) |
NV_TX_VALID = (1 shl 31) |
NV_TX2_LASTPACKET = (1 shl 29) |
NV_TX2_RETRYERROR = (1 shl 18) |
NV_TX2_LASTPACKET1 = (1 shl 23) |
NV_TX2_DEFERRED = (1 shl 25) |
NV_TX2_CARRIERLOST = (1 shl 26) |
NV_TX2_LATECOLLISION = (1 shl 27) |
NV_TX2_UNDERFLOW = (1 shl 28) |
; error and valid are the same for both |
NV_TX2_ERROR = (1 shl 30) |
NV_TX2_VALID = (1 shl 31) |
NV_RX_DESCRIPTORVALID = (1 shl 16) |
NV_RX_AVAIL = (1 shl 31) |
NV_RX2_DESCRIPTORVALID = (1 shl 29) |
FLAG_MASK_V1 = 0xffff0000 |
FLAG_MASK_V2 = 0xffffc000 |
LEN_MASK_V1 = (0xffffffff xor FLAG_MASK_V1) |
LEN_MASK_V2 = (0xffffffff xor FLAG_MASK_V2) |
; Miscelaneous hardware related defines: |
NV_PCI_REGSZ_VER1 = 0x270 |
NV_PCI_REGSZ_VER2 = 0x604 |
; various timeout delays: all in usec |
NV_TXRX_RESET_DELAY = 4 |
NV_TXSTOP_DELAY1 = 10 |
NV_TXSTOP_DELAY1MAX = 500000 |
NV_TXSTOP_DELAY2 = 100 |
NV_RXSTOP_DELAY1 = 10 |
NV_RXSTOP_DELAY1MAX = 500000 |
NV_RXSTOP_DELAY2 = 100 |
NV_SETUP5_DELAY = 5 |
NV_SETUP5_DELAYMAX = 50000 |
NV_POWERUP_DELAY = 5 |
NV_POWERUP_DELAYMAX = 5000 |
NV_MIIBUSY_DELAY = 50 |
NV_MIIPHY_DELAY = 10 |
NV_MIIPHY_DELAYMAX = 10000 |
NV_MAC_RESET_DELAY = 64 |
NV_WAKEUPPATTERNS = 5 |
NV_WAKEUPMASKENTRIES = 4 |
; Advertisement control register. |
ADVERTISE_SLCT = 0x001f ; Selector bits |
ADVERTISE_CSMA = 0x0001 ; Only selector supported |
ADVERTISE_10HALF = 0x0020 ; Try for 10mbps half-duplex |
ADVERTISE_10FULL = 0x0040 ; Try for 10mbps full-duplex |
ADVERTISE_100HALF = 0x0080 ; Try for 100mbps half-duplex |
ADVERTISE_100FULL = 0x0100 ; Try for 100mbps full-duplex |
ADVERTISE_100BASE4 = 0x0200 ; Try for 100mbps 4k packets |
ADVERTISE_RESV = 0x1c00 ; Unused... |
ADVERTISE_RFAULT = 0x2000 ; Say we can detect faults |
ADVERTISE_LPACK = 0x4000 ; Ack link partners response |
ADVERTISE_NPAGE = 0x8000 ; Next page bit |
ADVERTISE_FULL = (ADVERTISE_100FULL or ADVERTISE_10FULL or ADVERTISE_CSMA) |
ADVERTISE_ALL = (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL) |
MII_1000BT_CR = 0x09 |
MII_1000BT_SR = 0x0a |
ADVERTISE_1000FULL = 0x0200 |
ADVERTISE_1000HALF = 0x0100 |
BMCR_ANRESTART = 0x0200 ; Auto negotiation restart |
BMCR_ANENABLE = 0x1000 ; Enable auto negotiation |
BMCR_SPEED100 = 0x2000 ; Select 100Mbps |
BMCR_LOOPBACK = 0x4000 ; TXD loopback bits |
BMCR_RESET = 0x8000 ; Reset the DP83840 |
; Basic mode status register. |
BMSR_ERCAP = 0x0001 ; Ext-reg capability |
BMSR_JCD = 0x0002 ; Jabber detected |
BMSR_LSTATUS = 0x0004 ; Link status |
BMSR_ANEGCAPABLE = 0x0008 ; Able to do auto-negotiation |
BMSR_RFAULT = 0x0010 ; Remote fault detected |
BMSR_ANEGCOMPLETE = 0x0020 ; Auto-negotiation complete |
BMSR_RESV = 0x07c0 ; Unused... |
BMSR_10HALF = 0x0800 ; Can do 10mbps, half-duplex |
BMSR_10FULL = 0x1000 ; Can do 10mbps, full-duplex |
BMSR_100HALF = 0x2000 ; Can do 100mbps, half-duplex |
BMSR_100FULL = 0x4000 ; Can do 100mbps, full-duplex |
BMSR_100BASE4 = 0x8000 ; Can do 100mbps, 4k packets |
struct TxDesc |
PacketBuffer dd ? |
FlagLen dd ? |
ends |
struct RxDesc |
PacketBuffer dd ? |
FlagLen dd ? |
ends |
virtual at ebx |
device: |
ETH_DEVICE |
.pci_bus dd ? |
.pci_dev dd ? |
.mmio_addr dd ? |
.vendor_id dw ? |
.device_id dw ? |
.txflags dd ? |
.desc_ver dd ? |
.irqmask dd ? |
.wolenabled dd ? |
.in_shutdown dd ? |
.cur_rx dd ? |
.phyaddr dd ? |
.phy_oui dd ? |
.gigabit dd ? |
.needs_mac_reset dd ? |
.linkspeed dd ? |
.duplex dd ? |
.next_tx dd ? |
.nocable dd ? |
rb 0x100 - (($ - device) and 0xff) |
.tx_ring rd (TX_RING * sizeof.TxDesc) /4*2 |
rb 0x100 - (($ - device) and 0xff) |
.rx_ring rd (RX_RING * sizeof.RxDesc) /4*2 |
sizeof.device_struct = $ - device |
end virtual |
virtual at edi |
IrqStatus dd ? |
IrqMask dd ? |
UnknownSetupReg6 dd ? |
PollingInterval dd ? |
end virtual |
virtual at edi + 0x3c |
MacReset dd ? |
end virtual |
virtual at edi + 0x80 |
Misc1 dd ? |
TransmitterControl dd ? |
TransmitterStatus dd ? |
PacketFilterFlags dd ? |
OffloadConfig dd ? |
ReceiverControl dd ? |
ReceiverStatus dd ? |
RandomSeed dd ? |
UnknownSetupReg1 dd ? |
UnknownSetupReg2 dd ? |
MacAddrA dd ? |
MacAddrB dd ? |
MulticastAddrA dd ? |
MulticastAddrB dd ? |
MulticastMaskA dd ? |
MulticastMaskB dd ? |
PhyInterface dd ? |
end virtual |
virtual at edi + 0x100 |
TxRingPhysAddr dd ? |
RxRingPhysAddr dd ? |
RingSizes dd ? |
UnknownTransmitterReg dd ? |
LinkSpeed dd ? |
end virtual |
virtual at edi + 0x130 |
UnknownSetupReg5 dd ? |
end virtual |
virtual at edi + 0x13c |
UnknownSetupReg3 dd ? |
end virtual |
virtual at edi + 0x144 |
TxRxControl dd ? |
end virtual |
virtual at edi + 0x180 |
MIIStatus dd ? |
UnknownSetupReg4 dd ? |
AdapterControl dd ? |
MIISpeed dd ? |
MIIControl dd ? |
MIIData dd ? |
end virtual |
virtual at edi + 0x200 |
WakeUpFlags dd ? |
end virtual |
virtual at edi + 0x26c |
PowerState dd ? |
end virtual |
virtual at edi + 0x600 |
PowerState2 dd ? |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax, [eax+1] |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte) |
jne @f |
cmp ah, byte [device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], .fail |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte [eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte [eax+2] |
mov [device.pci_dev], ecx |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x\n", [device.pci_dev], [device.pci_bus] |
; Ok, the eth_device structure is ready, let's probe the device |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, ebx |
.fail: |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;*************************************************************************** |
; Function |
; probe |
; Description |
; Searches for an ethernet card, enables it and clears the rx buffer |
; |
;*************************************************************************** |
align 4 |
probe: |
DEBUGF 1,"probe\n" |
mov [device.needs_mac_reset], 0 |
PCI_make_bus_master |
PCI_adjust_latency 32 |
PCI_find_mmio32 |
DEBUGF 1,"mmio_addr= 0x%x\n", [device.mmio_addr]:8 |
stdcall MapIoMem, [device.mmio_addr], 2048, (PG_SW + PG_NOCACHE) |
test eax, eax |
jz fail |
mov [device.mmio_addr], eax |
mov edi, eax |
DEBUGF 1,"mapped mmio_addr= 0x%x\n", [device.mmio_addr]:8 |
;------------------------------------- |
; handle different descriptor versions |
mov [device.desc_ver], DESC_VER_1 |
movzx eax, [device.device_id] |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_1 |
je .ver1 |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_2 |
je .ver1 |
cmp eax, PCI_DEVICE_ID_NVIDIA_NVENET_3 |
je .ver1 |
mov [device.desc_ver], DESC_VER_2 |
.ver1: |
call read_mac |
; disable WOL |
mov [WakeUpFlags], 0 |
mov [device.wolenabled], 0 |
mov [device.txflags], (NV_TX2_LASTPACKET or NV_TX2_VALID) |
cmp [device.desc_ver], DESC_VER_1 |
jne @f |
mov [device.txflags], (NV_TX_LASTPACKET or NV_TX_VALID) |
@@: |
; BEGIN of switch (pci->dev_id) |
cmp [device.device_id], 0x01C3 |
jne .next_0x0066 |
; nforce |
mov [device.irqmask], 0 ;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) |
jmp .find_phy |
.next_0x0066: |
cmp [device.device_id], 0x0066 |
je @f |
cmp [device.device_id], 0x00D6 |
je @f |
jmp .next_0x0086 |
@@: |
mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) |
cmp [device.desc_ver], DESC_VER_1 |
jne @f |
or [device.txflags], NV_TX_LASTPACKET1 |
jmp .find_phy |
@@: |
or [device.txflags], NV_TX2_LASTPACKET1 |
jmp .find_phy |
.next_0x0086: |
cmp [device.device_id], 0x0086 |
je @f |
cmp [device.device_id], 0x008c |
je @f |
cmp [device.device_id], 0x00e6 |
je @f |
cmp [device.device_id], 0x00df |
je @f |
cmp [device.device_id], 0x0056 |
je @f |
cmp [device.device_id], 0x0057 |
je @f |
cmp [device.device_id], 0x0037 |
je @f |
cmp [device.device_id], 0x0038 |
je @f |
jmp .find_phy |
@@: |
mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) |
cmp [device.desc_ver], DESC_VER_1 |
jne @f |
or [device.txflags], NV_TX_LASTPACKET1 |
jmp .find_phy |
@@: |
or [device.txflags], NV_TX2_LASTPACKET1 |
jmp .find_phy |
.next_0x0268: |
; cmp word [device_id], 0x0268 |
; je @f |
; cmp word [device_id], 0x0269 |
; je @f |
; cmp word [device_id], 0x0372 |
; je @f |
; cmp word [device_id], 0x0373 |
; je @f |
; jmp .default_switch |
;@@: |
cmp [device.device_id], 0x0268 |
jb .undefined |
; Get device revision |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REVISION_ID |
; take phy and nic out of low power mode |
mov ecx, [PowerState2] |
and ecx, not POWERSTATE2_POWERUP_MASK |
cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_12 |
jne @f |
cmp [device.device_id], PCI_DEVICE_ID_NVIDIA_NVENET_13 |
jne @f |
cmp al, 0xA3 |
jb @f |
or ecx, POWERSTATE2_POWERUP_REV_A3 |
@@: |
mov [PowerState2], ecx |
; DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ |
mov [device.irqmask], 0 ;;;;;;;;;;;;;;;;(IRQMASK_WANTED_2 or IRQ_TIMER) |
mov [device.needs_mac_reset], 1 |
cmp [device.desc_ver], DESC_VER_1 |
jne @f |
or [device.txflags], NV_TX_LASTPACKET1 |
jmp .find_phy |
@@: |
cmp [device.desc_ver], DESC_VER_2 |
jne .undefined |
or [device.txflags], NV_TX2_LASTPACKET1 |
jmp .find_phy |
.undefined: |
DEBUGF 1,"Your card was undefined in this driver.\n" |
DEBUGF 1,"Review driver_data in Kolibri driver and send a patch\n" |
; Find a suitable phy |
; Start with address 1 to 31, then do 0, then fail |
.find_phy: |
xor edx, edx |
.phy_loop: |
inc edx |
and edx, 0x1f ; phyaddr = i & 0x1f |
mov eax, MII_PHYSID1 |
mov ecx, MII_READ |
call mii_rw ; EDX - addr, EAX - miireg, ECX - value |
cmp eax, 0xffff |
je .try_next |
cmp eax, 0 |
jl .try_next |
mov esi, eax |
mov eax, MII_PHYSID2 |
mov ecx, MII_READ |
call mii_rw |
cmp eax, 0xffff |
je .try_next |
cmp eax, 0 |
jl .try_next |
jmp .got_it |
.try_next: |
test edx, edx |
jnz .phy_loop |
; PHY in isolate mode? No phy attached and user wants to test loopback? |
; Very odd, but can be correct. |
DEBUGF 1,"Could not find a valid PHY.\n" |
jmp .no_phy |
.got_it: |
and esi, PHYID1_OUI_MASK |
shl esi, PHYID1_OUI_SHFT |
and eax, PHYID2_OUI_MASK |
shr eax, PHYID2_OUI_SHFT |
DEBUGF 1,"Found PHY 0x%x:0x%x at address 0x%x\n", esi:8, eax:8, edx |
mov [device.phyaddr], edx |
or eax, esi |
mov [device.phy_oui], eax |
call phy_init |
.no_phy: |
cmp [device.needs_mac_reset], 0 |
je @f |
call mac_reset |
@@: |
;*************************************************************************** |
; Function |
; reset |
; Description |
; Place the chip (ie, the ethernet card) into a virgin state |
; No inputs |
; All registers destroyed |
; |
;*************************************************************************** |
reset: |
DEBUGF 1,"Resetting\n" |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_IRQ |
movzx eax, al |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
; erase previous misconfiguration |
mov edi, [device.mmio_addr] |
mov [MulticastAddrA], MCASTADDRA_FORCE |
mov [MulticastAddrB], 0 |
mov [MulticastMaskA], 0 |
mov [MulticastMaskB], 0 |
mov [PacketFilterFlags], 0 |
mov [TransmitterControl], 0 |
mov [ReceiverControl], 0 |
mov [AdapterControl], 0 |
; initialize descriptor rings |
call init_ring |
mov [LinkSpeed], 0 |
mov [UnknownTransmitterReg], 0 |
call txrx_reset |
mov [UnknownSetupReg6], 0 |
mov [device.in_shutdown], 0 |
; give hw rings |
lea eax, [device.rx_ring] |
GetRealAddr |
mov [RxRingPhysAddr], eax |
lea eax, [device.tx_ring] |
GetRealAddr |
mov [TxRingPhysAddr], eax |
mov [RingSizes], (((RX_RING - 1) shl RINGSZ_RXSHIFT) + ((TX_RING - 1) shl RINGSZ_TXSHIFT)) |
; |
mov [device.linkspeed], (LINKSPEED_FORCE or LINKSPEED_10) |
mov [device.duplex], 0 |
mov [LinkSpeed], (LINKSPEED_FORCE or LINKSPEED_10) |
mov [UnknownSetupReg3], UNKSETUP3_VAL1 |
mov eax, [device.desc_ver] |
mov [TxRxControl], eax |
call pci_push |
or eax, TXRXCTL_BIT1 |
mov [TxRxControl], eax |
stdcall reg_delay, UnknownSetupReg5-edi, UNKSETUP5_BIT31, UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, 0 |
mov [UnknownSetupReg4], 0 |
mov [MIIStatus], MIISTAT_MASK2 |
; |
mov [Misc1], (MISC1_FORCE or MISC1_HD) |
mov eax, [TransmitterStatus] |
mov [TransmitterStatus], eax |
mov [PacketFilterFlags], PFF_ALWAYS |
mov [OffloadConfig], OFFLOAD_NORMAL |
mov eax, [ReceiverStatus] |
mov [ReceiverStatus], eax |
; set random seed |
push ebx |
stdcall GetTimerTicks ; bad idea, driver is started at system startup in 90% of cases.. |
pop ebx |
mov edi, [device.mmio_addr] |
and eax, RNDSEED_MASK |
or eax, RNDSEED_FORCE |
mov [RandomSeed], eax |
mov [UnknownSetupReg1], UNKSETUP1_VAL |
mov [UnknownSetupReg2], UNKSETUP2_VAL |
mov [PollingInterval], POLL_DEFAULT |
mov [UnknownSetupReg6], UNKSETUP6_VAL |
mov eax, [device.phyaddr] |
shl eax, ADAPTCTL_PHYSHIFT |
or eax, (ADAPTCTL_PHYVALID or ADAPTCTL_RUNNING) |
mov [AdapterControl], eax |
mov [MIISpeed], (MIISPEED_BIT8 or MIIDELAY) |
mov [UnknownSetupReg4], UNKSETUP4_VAL |
mov [WakeUpFlags], WAKEUPFLAGS_VAL |
or [PowerState], POWERSTATE_POWEREDUP |
call pci_push |
mov esi, 10 |
call Sleep |
or [PowerState], POWERSTATE_VALID |
mov [IrqMask], 0 |
;;; ; ??? Mask RX interrupts |
mov [IrqMask], IRQ_RX_ALL + IRQ_TX_ALL |
;;; ; ??? Mask TX interrupts |
;;; mov [IrqMask], IRQ_TX_ALL |
;;; ; ??? Mask OTHER interrupts |
;;; mov [IrqMask], IRQ_OTHER_ALL |
call pci_push |
mov [MIIStatus], MIISTAT_MASK2 |
mov [IrqStatus], IRQSTAT_MASK |
call pci_push |
mov [MulticastAddrA], MCASTADDRA_FORCE |
mov [MulticastAddrB], 0 |
mov [MulticastMaskA], 0 |
mov [MulticastMaskB], 0 |
mov [PacketFilterFlags], (PFF_ALWAYS or PFF_MYADDR) |
call set_multicast |
; One manual link speed update: Interrupts are enabled, future link |
; speed changes cause interrupts and are handled by nv_link_irq(). |
mov eax, [MIIStatus] |
mov [MIIStatus], MIISTAT_MASK |
DEBUGF 1,"startup: got 0x%x\n", eax |
call update_linkspeed |
mov [TransmitterControl], XMITCTL_START ; start TX |
call pci_push |
mov [device.nocable], 0 |
test eax, eax |
jnz .return |
DEBUGF 1,"no link during initialization.\n" |
mov [device.nocable], 1 |
.return: |
xor eax, eax ; Indicate that we have successfully reset the card |
mov [device.mtu], 1514 ;;; FIXME |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
ret |
fail: |
or eax, -1 |
ret |
;-------------------------------------------------------- |
; |
; MII_RW |
; |
; read/write a register on the PHY. |
; Caller must guarantee serialization |
; Input: EAX - miireg, EDX - addr, ECX - value |
; Output: EAX - retval |
; |
;-------------------------------------------------------- |
mii_rw: |
DEBUGF 1,"mii_rw: 0x%x to reg %d at PHY %d\n", ecx, eax, edx |
push edx |
mov edi, [device.mmio_addr] |
mov [MIIStatus], MIISTAT_MASK |
test [MIIControl], MIICTL_INUSE |
jz @f |
mov [MIIControl], MIICTL_INUSE |
mov esi, NV_MIIBUSY_DELAY |
call Sleep |
@@: |
shl edx, MIICTL_ADDRSHIFT |
or edx, eax |
cmp ecx, MII_READ |
je @f |
mov [MIIData], ecx |
or edx, MIICTL_WRITE |
@@: |
mov [MIIControl], edx |
stdcall reg_delay, MIIControl-edi, MIICTL_INUSE, 0, NV_MIIPHY_DELAY, NV_MIIPHY_DELAYMAX, 0 |
test eax, eax |
jz @f |
DEBUGF 1,"mii_rw timed out.\n" |
or eax, -1 |
jmp .return |
@@: |
cmp ecx, MII_READ |
je @f |
; it was a write operation - fewer failures are detectable |
DEBUGF 1,"mii_rw write: ok\n" |
xor eax, eax |
jmp .return |
@@: |
mov eax, [MIIStatus] |
test eax, MIISTAT_ERROR |
jz @f |
DEBUGF 1,"mii read: failed.\n" |
or eax, -1 |
jmp .return |
@@: |
mov eax, [MIIData] |
DEBUGF 1,"mii read: 0x%x.\n", eax |
.return: |
pop edx |
ret |
; Input: offset:word, mask:dword, target:dword, delay:word, delaymax:word, msg:dword |
; Output: EAX - 0|1 |
proc reg_delay, offset:dword, mask:dword, target:dword, delay:dword, delaymax:dword, msg:dword |
; DEBUGF 1,"reg_delay\n" |
push esi |
call pci_push |
.loop: |
mov esi, [delay] |
call Sleep |
mov eax, [delaymax] |
sub eax, [delay] |
mov [delaymax], eax |
cmp eax, 0 |
jl .fail |
mov eax, [offset] |
mov eax, [edi + eax] |
and eax, [mask] |
cmp eax, [target] |
jne .loop |
pop esi |
xor eax, eax |
ret |
.fail: |
pop esi |
xor eax, eax |
inc eax |
ret |
endp |
; Input: none |
; Output: EAX - result (0 = OK, other = error) |
phy_init: |
push ebx ecx |
; set advertise register |
mov edx, [device.phyaddr] |
mov eax, MII_ADVERTISE |
mov ecx, MII_READ |
call mii_rw |
or eax, (ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL or 0x800 or 0x400) |
mov ecx, eax |
mov eax, MII_ADVERTISE |
call mii_rw |
test eax, eax |
jz @f |
DEBUGF 1,"phy write to advertise failed.\n" |
mov eax, PHY_ERROR |
jmp .return |
@@: |
; get phy interface type |
mov edi, [device.mmio_addr] |
mov eax, [PhyInterface] |
DEBUGF 1,"phy interface type = 0x%x\n", eax:8 |
; see if gigabit phy |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call mii_rw |
test eax, PHY_GIGABIT |
jnz .gigabit |
mov [device.gigabit], 0 |
jmp .next_if |
.gigabit: |
mov [device.gigabit], PHY_GIGABIT |
mov eax, MII_1000BT_CR |
mov ecx, MII_READ |
call mii_rw |
and eax, (not ADVERTISE_1000HALF) |
test [PhyInterface], PHY_RGMII |
jz @f |
or eax, ADVERTISE_1000FULL |
jmp .next |
@@: |
and eax, (not ADVERTISE_1000FULL) |
.next: |
mov ecx, eax |
mov eax, MII_1000BT_CR |
call mii_rw |
test eax, eax |
jz .next_if |
DEBUGF 1,"phy init failed.\n" |
mov eax, PHY_ERROR |
jmp .return |
.next_if: |
call phy_reset |
test eax, eax |
jz @f |
DEBUGF 1,"phy reset failed.\n" |
mov eax, PHY_ERROR |
jmp .return |
@@: |
; phy vendor specific configuration |
cmp [device.phy_oui], PHY_OUI_CICADA |
jne .next_if2 |
test [PhyInterface], PHY_RGMII |
jz .next_if2 |
mov eax, MII_RESV1 |
mov ecx, MII_READ |
call mii_rw |
and eax, (not (PHY_INIT1 or PHY_INIT2)) |
or eax, (PHY_INIT3 or PHY_INIT4) |
mov ecx, eax |
mov eax, MII_RESV1 |
call mii_rw |
test eax, eax |
jz @f |
DEBUGF 1,"phy init failed.\n" |
mov eax, PHY_ERROR |
jmp .return |
@@: |
mov eax, MII_NCONFIG |
mov ecx, MII_READ |
call mii_rw |
or eax, PHY_INIT5 |
mov ecx, eax |
mov eax, MII_NCONFIG |
call mii_rw |
test eax, eax |
jz .next_if2 |
DEBUGF 1,"phy init failed.\n" |
mov eax, PHY_ERROR |
jmp .return |
.next_if2: |
cmp [device.phy_oui], PHY_OUI_CICADA |
jne .restart |
mov eax, MII_SREVISION |
mov ecx, MII_READ |
call mii_rw |
or eax, PHY_INIT6 |
mov ecx, eax |
mov eax, MII_SREVISION |
call mii_rw |
test eax, eax |
jz .restart |
DEBUGF 1,"phy init failed.\n" |
jmp .return |
.restart: |
; restart auto negotiation |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call mii_rw |
or eax, (BMCR_ANRESTART or BMCR_ANENABLE) |
mov ecx, eax |
mov eax, MII_BMCR |
call mii_rw |
test eax, eax |
jz .ok |
mov eax, PHY_ERROR |
jmp .return |
.ok: |
xor eax, eax |
.return: |
pop ecx ebx |
ret |
; Input: none |
; Output: EAX - result (0 = OK, other = error) |
phy_reset: |
DEBUGF 1,"phy_reset\n" |
push ebx ecx edx |
mov edx, [device.phyaddr] |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call mii_rw |
or eax, BMCR_RESET |
push eax |
mov ecx, eax |
mov eax, MII_BMCR |
call mii_rw |
test eax, eax |
jz @f |
pop eax |
mov eax, 0xffffffff |
jmp .return |
@@: |
pop eax |
mov esi, 500 |
call Sleep |
; must wait till reset is deasserted |
mov esi, 100 ; FIXME: 100 tries seem excessive |
.while_loop: |
test eax, BMCR_RESET |
jz .while_loop_exit |
push esi |
mov esi, 10 |
call Sleep |
pop esi |
mov eax, MII_BMCR |
mov ecx, MII_READ |
call mii_rw |
dec esi |
jnz .while_loop |
mov eax, 0xffffffff |
jmp .return |
.while_loop_exit: |
xor eax, eax |
.return: |
pop edx ecx ebx |
ret |
align 4 |
pci_push: |
push eax |
mov eax, [edi] |
pop eax |
ret |
align 4 |
mac_reset: |
push esi edi |
DEBUGF 1,"mac_reset.\n" |
mov edi, [device.mmio_addr] |
mov eax, [device.desc_ver] |
or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) |
mov [TxRxControl], eax |
call pci_push |
mov [MacReset], MAC_RESET_ASSERT |
call pci_push |
mov esi, NV_MAC_RESET_DELAY |
call Sleep |
mov [MacReset], 0 |
call pci_push |
mov esi, NV_MAC_RESET_DELAY |
call Sleep |
mov eax, [device.desc_ver] |
or eax, TXRXCTL_BIT2 |
mov [TxRxControl], eax |
call pci_push |
pop edi esi |
ret |
align 4 |
init_ring: |
DEBUGF 1,"init rings\n" |
push eax esi ecx |
mov [device.next_tx], 0 |
mov ecx, TX_RING |
lea esi, [device.tx_ring] |
.tx_loop: |
mov [esi + TxDesc.FlagLen], 0 |
add esi, sizeof.TxDesc |
dec ecx |
jnz .tx_loop |
mov [device.cur_rx], 0 |
mov ecx, RX_RING |
lea esi, [device.rx_ring] |
.rx_loop: |
push ecx esi |
stdcall KernelAlloc, 4096 shl RBLEN ; push/pop esi not needed, but just in case... |
pop esi |
mov [esi + RX_RING*sizeof.RxDesc], eax |
GetRealAddr |
mov [esi + RxDesc.PacketBuffer], eax |
mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) |
add esi, sizeof.RxDesc |
pop ecx |
dec ecx |
jnz .rx_loop |
pop ecx esi eax |
ret |
; Input: none |
; Output: none |
align 4 |
txrx_reset: |
push eax esi |
DEBUGF 1,"txrx_reset\n" |
mov edi, [device.mmio_addr] |
mov eax, [device.desc_ver] |
or eax, (TXRXCTL_BIT2 or TXRXCTL_RESET) |
mov [TxRxControl], eax |
call pci_push |
mov esi, NV_TXRX_RESET_DELAY |
call Sleep |
mov eax, [device.desc_ver] |
or eax, TXRXCTL_BIT2 |
mov [TxRxControl], eax |
call pci_push |
pop esi eax |
ret |
; Input: none |
; Output: none |
set_multicast: |
; u32 addr[2]; |
; u32 mask[2]; |
; u32 pff; |
; u32 alwaysOff[2]; |
; u32 alwaysOn[2]; |
; |
; memset(addr, 0, sizeof(addr)); |
; memset(mask, 0, sizeof(mask)); |
; |
; pff = PFF_MYADDR; |
; |
; alwaysOn[0] = alwaysOn[1] = alwaysOff[0] = alwaysOff[1] = 0; |
; |
; addr[0] = alwaysOn[0]; |
; addr[1] = alwaysOn[1]; |
; mask[0] = alwaysOn[0] | alwaysOff[0]; |
; mask[1] = alwaysOn[1] | alwaysOff[1]; |
; |
; addr[0] |= MCASTADDRA_FORCE; |
; pff |= PFF_ALWAYS; |
call stop_rx |
mov edi, [device.mmio_addr] |
mov [MulticastAddrA], MCASTADDRA_FORCE |
mov [MulticastAddrB], 0 |
mov [MulticastMaskA], 0 |
mov [MulticastMaskB], 0 |
mov [PacketFilterFlags], (PFF_MYADDR or PFF_ALWAYS) |
call start_rx |
ret |
; Input: none |
; Output: none |
start_rx: |
push edi |
DEBUGF 1,"start_rx\n" |
; Already running? Stop it. |
mov edi, [device.mmio_addr] |
mov eax, [ReceiverControl] |
test eax, RCVCTL_START |
jz @f |
mov [ReceiverControl], 0 |
call pci_push |
@@: |
mov eax, [device.linkspeed] |
mov [LinkSpeed], eax |
call pci_push |
mov [ReceiverControl], RCVCTL_START |
call pci_push |
pop edi |
ret |
; Input: none |
; Output: none |
stop_rx: |
push esi edi |
DEBUGF 1,"stop_rx.\n" |
mov edi, [device.mmio_addr] |
mov [ReceiverControl], 0 |
push ebx edx edi |
stdcall reg_delay, ReceiverStatus-edi, RCVSTAT_BUSY, 0, NV_RXSTOP_DELAY1, NV_RXSTOP_DELAY1MAX, 0 |
pop edi edx ebx |
mov esi, NV_RXSTOP_DELAY2 |
call Sleep |
mov [LinkSpeed], 0 |
pop edi esi |
ret |
; Input: none |
; Output: EAX |
update_linkspeed: |
DEBUGF 1,"update linkspeed\n" |
; BMSR_LSTATUS is latched, read it twice: we want the current value. |
mov edx, [device.phyaddr] |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call mii_rw |
mov eax, MII_BMSR |
mov ecx, MII_READ |
call mii_rw |
test eax, BMSR_LSTATUS ; Link up? |
jz .10mbit_hd |
test eax, BMSR_ANEGCOMPLETE ; still in autonegotiation? |
jz .10mbit_hd |
cmp [device.gigabit], PHY_GIGABIT |
jne .no_gigabit |
;mov edx, [device.phyaddr] |
mov eax, MII_1000BT_CR |
mov ecx, MII_READ |
call mii_rw |
push eax |
;mov edx, [device.phyaddr] |
mov eax, MII_1000BT_SR |
mov ecx, MII_READ |
call mii_rw |
pop ecx |
test eax, LPA_1000FULL |
jz .no_gigabit |
test ecx, ADVERTISE_1000FULL |
jz .no_gigabit |
DEBUGF 1,"update_linkspeed: GBit ethernet detected.\n" |
mov ecx, (LINKSPEED_FORCE or LINKSPEED_1000) |
xor eax, eax |
inc eax |
jmp set_speed |
.no_gigabit: |
;mov edx, [device.phyaddr] |
mov eax, MII_ADVERTISE |
mov ecx, MII_READ |
call mii_rw ; adv = eax |
push eax |
;mov edx, [device.phyaddr] |
mov eax, MII_LPA |
mov ecx, MII_READ |
call mii_rw ; lpa = eax |
pop ecx |
DEBUGF 1,"PHY advertises 0x%x, lpa 0x%x\n", ecx, eax |
and eax, ecx ; FIXME: handle parallel detection properly, handle gigabit ethernet |
test eax, LPA_100FULL |
jz @f |
DEBUGF 1,"update_linkspeed: 100 mbit full duplex\n" |
mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) |
xor eax, eax |
inc eax |
jmp set_speed |
@@: |
test eax, LPA_100HALF |
jz @f |
DEBUGF 1,"update_linkspeed: 100 mbit half duplex\n" |
mov ecx, (LINKSPEED_FORCE or LINKSPEED_100) |
xor eax, eax |
jmp set_speed |
@@: |
test eax, LPA_10FULL |
jz @f |
DEBUGF 1,"update_linkspeed: 10 mbit full duplex\n" |
mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) |
xor eax, eax |
inc eax |
jmp set_speed |
@@: |
.10mbit_hd: |
DEBUGF 1,"update_linkspeed: 10 mbit half duplex\n" |
mov ecx, (LINKSPEED_FORCE or LINKSPEED_10) |
xor eax, eax |
jmp set_speed |
align 4 |
set_speed: |
cmp eax, [device.duplex] |
jne .update |
cmp ecx, [device.linkspeed] |
jne .update |
ret |
.update: |
DEBUGF 1,"update_linkspeed: changing link to 0x%x/XD.\n", ecx |
mov [device.duplex], eax |
mov [device.linkspeed], ecx |
cmp [device.gigabit], PHY_GIGABIT |
jne .no_gigabit |
mov edi, [device.mmio_addr] |
mov eax, [RandomSeed] |
and eax, not (0x3FF00) |
mov ecx, eax ; phyreg = ecx |
mov eax, [device.linkspeed] |
and eax, 0xFFF |
cmp eax, LINKSPEED_10 |
jne @f |
or ecx, RNDSEED_FORCE3 |
jmp .end_if4 |
@@: |
cmp eax, LINKSPEED_100 |
jne @f |
or ecx, RNDSEED_FORCE2 |
jmp .end_if4 |
@@: |
cmp eax, LINKSPEED_1000 |
jne .end_if4 |
or ecx, RNDSEED_FORCE |
.end_if4: |
mov [RandomSeed], ecx |
.no_gigabit: |
mov ecx, [PhyInterface] |
and ecx, not (PHY_HALF or PHY_100 or PHY_1000) |
cmp [device.duplex], 0 |
jne @f |
or ecx, PHY_HALF |
@@: |
mov eax, [device.linkspeed] |
and eax, 0xFFF |
cmp eax, LINKSPEED_100 |
jne @f |
or ecx, PHY_100 |
jmp .end_if5 |
@@: |
cmp eax, LINKSPEED_1000 |
jne .end_if5 |
or ecx, PHY_1000 |
.end_if5: |
mov [PhyInterface], ecx |
cmp [device.duplex], 0 |
je @f |
xor ecx, ecx |
jmp .next |
@@: |
mov ecx, MISC1_HD |
.next: |
or ecx, MISC1_FORCE |
mov [Misc1], ecx |
call pci_push |
mov eax, [device.linkspeed] |
mov [LinkSpeed], eax |
call pci_push |
ret |
align 4 |
read_mac: |
mov edi, [device.mmio_addr] |
mov eax, [MacAddrA] |
mov ecx, [MacAddrB] |
mov dword [device.mac], eax |
mov word [device.mac + 4], cx |
cmp [device.device_id], 0x03E5 |
jae @f |
bswap eax |
xchg cl, ch |
mov dword [device.mac + 2], eax |
mov word [device.mac], cx |
@@: |
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n", \ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp + 8], 1514 |
ja .fail |
cmp dword [esp + 8], 60 |
jb .fail |
; get the descriptor address |
mov eax, [device.next_tx] |
mov cl, sizeof.TxDesc |
mul cl |
lea esi, [device.tx_ring + eax] |
mov eax, [esp + 4] |
mov [esi + TX_RING*sizeof.TxDesc], eax |
GetRealAddr |
mov [esi + TxDesc.PacketBuffer], eax |
mov ecx, [esp + 8] |
or ecx, [device.txflags] |
mov [esi + TxDesc.FlagLen], eax |
mov edi, [device.mmio_addr] |
mov eax, [device.desc_ver] |
or eax, TXRXCTL_KICK |
mov [TxRxControl], eax |
call pci_push |
inc [device.next_tx] |
and [device.next_tx], (TX_RING-1) |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp + 8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
xor eax, eax |
ret 8 |
.fail: |
xor eax, eax |
inc eax |
ret 8 |
; Interrupt handler |
align 4 |
int_handler: |
DEBUGF 2,"\n%s INT\n", my_service |
;------------------------------------------- |
; Find pointer of device wich made IRQ occur |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .fail |
.nextdevice: |
mov ebx, dword [esi] |
add esi, 4 |
mov edi, [device.mmio_addr] |
mov eax, [IrqStatus] |
test eax, eax |
jnz .got_it |
dec ecx |
jnz .nextdevice |
ret |
.got_it: |
mov [IrqStatus], eax |
DEBUGF 2,"IrqStatus = %x\n", eax |
test eax, IRQ_RX |
jz .no_rx |
.top: |
mov eax, [device.cur_rx] |
mov cx, sizeof.RxDesc |
mul cx |
lea esi, [device.rx_ring + eax] |
mov eax, [esi + RxDesc.FlagLen] |
test eax, NV_RX_AVAIL ; still owned by hardware |
jnz .return0 |
cmp [device.desc_ver], DESC_VER_1 |
jne @f |
test eax, NV_RX_DESCRIPTORVALID |
jz .return0 |
jmp .next |
@@: |
test eax, NV_RX2_DESCRIPTORVALID |
jz .return0 |
.next: |
cmp dword [device.desc_ver], DESC_VER_1 |
jne @f |
and eax, LEN_MASK_V1 |
jmp .next2 |
@@: |
and eax, LEN_MASK_V2 |
.next2: |
; got a valid packet - forward it to the network core |
push .top |
push eax |
push dword [esi + RX_RING*sizeof.RxDesc] |
inc [device.cur_rx] |
and [device.cur_rx], (RX_RING-1) |
; Allocate new buffer |
stdcall KernelAlloc, 4096 shl RBLEN |
mov [esi + RX_RING*sizeof.RxDesc], eax |
GetRealAddr |
mov [esi + RxDesc.PacketBuffer], eax |
mov [esi + RxDesc.FlagLen], (4096 shl RBLEN or NV_RX_AVAIL) |
jmp Eth_input |
.return0: |
.no_rx: |
test eax, IRQ_RX_ERROR |
jz .no_rx_err |
push eax |
DEBUGF 2,"RX error!\n" |
mov eax, [device.cur_rx] |
mov cx, sizeof.RxDesc |
mul cx |
lea esi, [device.rx_ring + eax] |
mov eax, [esi + RxDesc.FlagLen] |
DEBUGF 2,"Flaglen=%x\n", eax |
; TODO: allocate new buff |
pop eax |
.no_rx_err: |
test eax, IRQ_LINK |
jz .no_link |
push eax |
call update_linkspeed |
pop eax |
.no_link: |
.fail: |
ret |
; End of code |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'FORCEDETH',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/i8255x.asm |
---|
0,0 → 1,1245 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; i8255x (Intel eepro 100) driver for KolibriOS ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Some parts of this driver are based on the code of eepro100.c ;; |
;; from linux. ;; |
;; ;; |
;; Intel's programming manual for i8255x: ;; |
;; http://www.intel.com/design/network/manuals/8255x_opensdm.htm ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.rx_desc dd ? |
.ee_bus_width db ? |
rb 0x100 - (($ - device) and 0xff) |
txfd: |
.status dw ? |
.command dw ? |
.link dd ? |
.tx_desc_addr dd ? |
.count dd ? |
.tx_buf_addr0 dd ? |
.tx_buf_size0 dd ? |
rb 0x100 - (($ - device) and 0xff) |
confcmd: |
.status dw ? |
.command dw ? |
.link dd ? |
.data rb 64 |
rb 0x100 - (($ - device) and 0xff) |
lstats: |
tx_good_frames dd ? |
tx_coll16_errs dd ? |
tx_late_colls dd ? |
tx_underruns dd ? |
tx_lost_carrier dd ? |
tx_deferred dd ? |
tx_one_colls dd ? |
tx_multi_colls dd ? |
tx_total_colls dd ? |
rx_good_frames dd ? |
rx_crc_errs dd ? |
rx_align_errs dd ? |
rx_resource_errs dd ? |
rx_overrun_errs dd ? |
rx_colls_errs dd ? |
rx_runt_errs dd ? |
last_tx_buffer dd ? ;;; fixme |
sizeof.device_struct = $ - device |
end virtual |
virtual at 0 |
rxfd: |
.status dw ? |
.command dw ? |
.link dd ? |
.rx_buf_addr dd ? |
.count dw ? |
.size dw ? |
.packet: |
end virtual |
; Serial EEPROM |
EE_SK = 1 shl 0 ; serial clock |
EE_CS = 1 shl 1 ; chip select |
EE_DI = 1 shl 2 ; data in |
EE_DO = 1 shl 3 ; data out |
EE_MASK = EE_SK + EE_CS + EE_DI + EE_DO |
; opcodes, first bit is start bit and must be 1 |
EE_READ = 110b |
EE_WRITE = 101b |
EE_ERASE = 111b |
; The SCB accepts the following controls for the Tx and Rx units: |
CU_START = 0x0010 |
CU_RESUME = 0x0020 |
CU_STATSADDR = 0x0040 |
CU_SHOWSTATS = 0x0050 ; Dump statistics counters. |
CU_CMD_BASE = 0x0060 ; Base address to add CU commands. |
CU_DUMPSTATS = 0x0070 ; Dump then reset stats counters. |
RX_START = 0x0001 |
RX_RESUME = 0x0002 |
RX_ABORT = 0x0004 |
RX_ADDR_LOAD = 0x0006 |
RX_RESUMENR = 0x0007 |
INT_MASK = 0x0100 |
DRVR_INT = 0x0200 ; Driver generated interrupt |
CmdIASetup = 0x0001 |
CmdConfigure = 0x0002 |
CmdTx = 0x0004 |
CmdTxFlex = 0x0008 |
Cmdsuspend = 0x4000 |
reg_scb_status = 0 |
reg_scb_cmd = 2 |
reg_scb_ptr = 4 |
reg_port = 8 |
reg_eeprom = 14 |
reg_mdi_ctrl = 16 |
macro delay { |
push eax |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
in ax, dx |
pop eax |
} |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 1,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, sizeof.device_struct, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Ok, the eth_device structure is ready, let's probe the device |
pushf |
cli ; disable ints until initialisation is done |
call probe ; this function will output in eax |
test eax, eax |
jnz .err ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
popf |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .err |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 2,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list (device_list) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
;------------- |
; |
; Probe |
; |
;------------- |
align 4 |
probe: |
DEBUGF 1,"Probing i8255x\n" |
PCI_make_bus_master |
;--------------------------- |
; First, identify the device |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], PCI_VENDOR_ID ; get device/vendor id |
DEBUGF 1,"Vendor_id=0x%x\n", ax |
cmp ax, 0x8086 |
jne .notfound |
shr eax, 16 |
DEBUGF 1,"Device_id=0x%x\n", ax |
mov ecx, DEVICE_IDs |
mov edi, device_id_list |
repne scasw |
jne .notfound |
jmp .found |
.notfound: |
DEBUGF 1,"ERROR: Unsupported device!\n" |
or eax, -1 |
ret |
.found: |
call ee_get_width |
call MAC_read_eeprom |
;;; TODO: detect phy |
;---------- |
; |
; Reset |
; |
;---------- |
align 4 |
reset: |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
DEBUGF 1,"Resetting %s\n", my_service |
;--------------- |
; reset the card |
set_io 0 |
set_io reg_port |
xor eax, eax ; Software Reset |
out dx, eax |
mov esi, 10 |
call Sleep ; Give the card time to warm up. |
;--------------------------------- |
; Tell device where to store stats |
lea eax, [lstats] |
GetRealAddr |
set_io 0 |
set_io reg_scb_ptr |
out dx, eax |
mov ax, INT_MASK + CU_STATSADDR |
set_io reg_scb_cmd |
out dx, ax |
call cmd_wait |
;----------------- |
; setup RX |
set_io reg_scb_ptr |
xor eax, eax |
out dx, eax |
set_io reg_scb_cmd |
mov ax, INT_MASK + RX_ADDR_LOAD |
out dx, ax |
call cmd_wait |
;----------------------------- |
; Create RX and TX descriptors |
call create_ring |
; RX start |
set_io 0 |
set_io reg_scb_ptr |
mov eax, [device.rx_desc] |
GetRealAddr |
out dx, eax |
mov ax, INT_MASK + RX_START |
set_io reg_scb_cmd |
out dx, ax |
call cmd_wait |
; Set-up TX |
set_io reg_scb_ptr |
xor eax, eax |
out dx, eax |
set_io reg_scb_cmd |
mov ax, INT_MASK + CU_CMD_BASE |
out dx, ax |
call cmd_wait |
; -------------------- |
mov [confcmd.command], CmdConfigure + Cmdsuspend |
mov [confcmd.status], 0 |
lea eax, [txfd] |
GetRealAddr |
mov [confcmd.link], eax |
mov esi, confcmd_data |
lea edi, [confcmd.data] |
mov ecx, 22 |
rep movsb |
mov byte[confcmd.data + 1], 0x88 ; fifo of 8 each |
mov byte[confcmd.data + 4], 0 |
mov byte[confcmd.data + 5], 0x80 |
mov byte[confcmd.data + 15], 0x48 |
mov byte[confcmd.data + 19], 0x80 |
mov byte[confcmd.data + 21], 0x05 |
mov [txfd.command], CmdIASetup |
mov [txfd.status], 0 |
lea eax, [confcmd] |
GetRealAddr |
mov [txfd.link], eax |
;;; copy in our MAC |
lea edi, [txfd.tx_desc_addr] |
lea esi, [device.mac] |
movsd |
movsw |
set_io reg_scb_ptr |
lea eax, [txfd] |
GetRealAddr |
out dx, eax |
; Start CU & enable ints |
set_io reg_scb_cmd |
mov ax, CU_START |
out dx, ax |
call cmd_wait |
;----------------------- |
; build txfd structure (again!) |
lea eax, [txfd] |
GetRealAddr |
mov [txfd.link], eax |
mov [txfd.count], 0x02208000 |
lea eax, [txfd.tx_buf_addr0] |
GetRealAddr |
mov [txfd.tx_desc_addr], eax |
; Indicate that we have successfully reset the card |
DEBUGF 1,"Resetting %s complete\n", my_service |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
xor eax, eax ; indicate that we have successfully reset the card |
ret |
align 4 |
create_ring: |
DEBUGF 1,"Creating ring\n" |
;--------------------- |
; build rxfd structure |
stdcall KernelAlloc, 2000 |
mov [device.rx_desc], eax |
mov esi, eax |
GetRealAddr |
mov [esi + rxfd.status], 0x0000 |
mov [esi + rxfd.command], 0x0000 |
mov [esi + rxfd.link], eax |
mov [esi + rxfd.count], 0 |
mov [esi + rxfd.size], 1528 |
;----------------------- |
; build txfd structure |
lea eax, [txfd] |
GetRealAddr |
mov [txfd.link], eax |
mov [txfd.count], 0x02208000 |
lea eax, [txfd.tx_buf_addr0] |
GetRealAddr |
mov [txfd.tx_desc_addr], eax |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], 1514 |
ja .error ; packet is too long |
cmp dword [esp+8], 60 |
jb .error ; packet is too short |
;;; TODO: check if current descriptor is in use |
; fill in buffer address and size |
mov eax, [esp+4] |
mov [last_tx_buffer], eax ;;; FIXME |
GetRealAddr |
mov [txfd.tx_buf_addr0], eax |
mov eax, [esp+8] |
mov [txfd.tx_buf_size0], eax |
mov [txfd.status], 0 |
mov [txfd.command], Cmdsuspend + CmdTx + CmdTxFlex + 1 shl 15 ;;; EL bit |
; mov [txfd.count], 0x02208000 ;;;;;;;;;;; |
; Inform device of the new/updated transmit descriptor |
lea eax, [txfd] |
GetRealAddr |
set_io 0 |
set_io reg_scb_ptr |
out dx, eax |
; Start the transmit |
mov ax, CU_START |
set_io reg_scb_cmd |
out dx, ax |
call cmd_wait |
; set_io 0 ;; why? |
; in ax, dx ;; |
; |
; @@: |
; cmp [txfd.status], 0 ; wait for completion? dont seems a good idea to me.. |
; je @r |
; |
; set_io 0 ;; why? |
; in ax, dx ;; |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp + 8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
DEBUGF 1,"Transmit OK\n" |
xor eax, eax |
ret 8 |
.error: |
stdcall KernelFree, [esp+4] |
or eax, -1 |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
; set_io 0 ; reg_scb_status = 0 |
set_io reg_scb_status |
in ax, dx |
out dx, ax ; send it back to ACK |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1,"Device: %x Status: %x\n", ebx, ax |
test ax, 1 shl 14 ; did we receive a frame? |
jz .no_rx |
push ax |
DEBUGF 1,"Receiving\n" |
push ebx |
.rx_loop: |
pop ebx |
mov esi, [device.rx_desc] |
cmp [esi + rxfd.status], 0 ; we could also check bits C and OK (bit 15 and 13) |
je .nodata |
DEBUGF 1,"rxfd status=0x%x\n", [esi + rxfd.status]:4 |
movzx ecx, [esi + rxfd.count] |
and ecx, 0x3fff |
push ebx |
push .rx_loop |
push ecx |
add esi, rxfd.packet |
push esi |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
; allocate new descriptor |
stdcall KernelAlloc, 2000 |
mov [device.rx_desc], eax |
mov esi, eax |
GetRealAddr |
mov [esi + rxfd.status], 0x0000 |
mov [esi + rxfd.command], 0xc000 ; End of list + Suspend |
mov [esi + rxfd.link], eax |
mov [esi + rxfd.count], 0 |
mov [esi + rxfd.size], 1528 |
; restart RX |
set_io 0 |
set_io reg_scb_ptr |
; lea eax, [device.rx_desc] |
; GetRealAddr |
out dx, eax |
set_io reg_scb_cmd |
mov ax, RX_START |
out dx, ax |
call cmd_wait |
; And give packet to kernel |
jmp Eth_input |
.nodata: |
DEBUGF 1, "no more data\n" |
pop ax |
.no_rx: |
; Cleanup after TX |
cmp [txfd.status], 0 |
je .done |
cmp [last_tx_buffer], 0 |
je .done |
push ax |
DEBUGF 1, "Removing packet 0x%x from RAM!\n", [last_tx_buffer] |
stdcall KernelFree, [last_tx_buffer] |
mov [last_tx_buffer], 0 |
pop ax |
.done: |
and ax, 00111100b |
cmp ax, 00001000b |
jne .fail |
DEBUGF 1, "out of resources!\n" |
; Restart the RX |
; allocate new descriptor |
stdcall KernelAlloc, 2000 |
mov [device.rx_desc], eax |
mov esi, eax |
GetRealAddr |
mov [esi + rxfd.status], 0x0000 |
mov [esi + rxfd.command], 0xc000 ; End of list + Suspend |
mov [esi + rxfd.link], eax |
mov [esi + rxfd.count], 0 |
mov [esi + rxfd.size], 1528 |
; restart RX |
set_io 0 |
set_io reg_scb_ptr |
; lea eax, [device.rx_desc] |
; GetRealAddr |
out dx, eax |
set_io reg_scb_cmd |
mov ax, RX_START |
out dx, ax |
call cmd_wait |
.fail: |
ret |
align 4 |
cmd_wait: |
in al, dx |
test al, al |
jnz cmd_wait |
ret |
align 4 |
ee_read: ; esi = address to read |
DEBUGF 1,"Eeprom read from 0x%x", esi |
set_io 0 |
set_io reg_eeprom |
;----------------------------------------------------- |
; Prepend start bit + read opcode to the address field |
; and shift it to the very left bits of esi |
mov cl, 29 |
sub cl, [device.ee_bus_width] |
shl esi, cl |
or esi, EE_READ shl 29 |
movzx ecx, [device.ee_bus_width] |
add ecx, 3 |
mov al, EE_CS |
out dx, al |
delay |
;----------------------- |
; Write this to the chip |
.loop: |
mov al, EE_CS + EE_SK |
shl esi, 1 |
jnc @f |
or al, EE_DI |
@@: |
out dx, al |
delay |
and al, not EE_SK |
out dx, al |
delay |
loop .loop |
;------------------------------ |
; Now read the data from eeprom |
xor esi, esi |
mov ecx, 16 |
.loop2: |
shl esi, 1 |
mov al, EE_CS + EE_SK |
out dx, al |
delay |
in al, dx |
test al, EE_DO |
jz @f |
inc esi |
@@: |
mov al, EE_CS |
out dx, al |
delay |
loop .loop2 |
;----------------------- |
; de-activate the eeprom |
xor ax, ax |
out dx, ax |
DEBUGF 1,"=0x%x\n", esi:4 |
ret |
align 4 |
ee_write: ; esi = address to write to, di = data |
DEBUGF 1,"Eeprom write 0x%x to 0x%x\n", di, esi |
set_io 0 |
set_io reg_eeprom |
;----------------------------------------------------- |
; Prepend start bit + write opcode to the address field |
; and shift it to the very left bits of esi |
mov cl, 29 |
sub cl, [device.ee_bus_width] |
shl esi, cl |
or esi, EE_WRITE shl 29 |
movzx ecx, [device.ee_bus_width] |
add ecx, 3 |
mov al, EE_CS ; enable chip |
out dx, al |
;----------------------- |
; Write this to the chip |
.loop: |
mov al, EE_CS + EE_SK |
shl esi, 1 |
jnc @f |
or al, EE_DI |
@@: |
out dx, al |
delay |
and al, not EE_SK |
out dx, al |
delay |
loop .loop |
;----------------------------- |
; Now write the data to eeprom |
mov ecx, 16 |
.loop2: |
mov al, EE_CS + EE_SK |
shl di, 1 |
jnc @f |
or al, EE_DI |
@@: |
out dx, al |
delay |
and al, not EE_SK |
out dx, al |
delay |
loop .loop2 |
;----------------------- |
; de-activate the eeprom |
xor al, al |
out dx, al |
ret |
align 4 |
ee_get_width: |
; DEBUGF 1,"Eeprom get width\n" |
set_io 0 |
set_io reg_eeprom |
mov al, EE_CS ; activate eeprom |
out dx, al |
delay |
mov si, EE_READ shl 13 |
xor ecx, ecx |
.loop: |
mov al, EE_CS + EE_SK |
shl si, 1 |
jnc @f |
or al, EE_DI |
@@: |
out dx, al |
delay |
and al, not EE_SK |
out dx, al |
delay |
inc ecx |
cmp ecx, 15 |
jae .give_up |
in al, dx |
test al, EE_DO |
jnz .loop |
.give_up: |
xor al, al |
out dx, al ; de-activate eeprom |
sub cl, 3 ; dont count the opcode bits |
mov [device.ee_bus_width], cl |
DEBUGF 1,"Eeprom width=%u bit\n", ecx |
;----------------------- |
; de-activate the eeprom |
xor eax, eax |
out dx, eax |
ret |
; cx = phy addr |
; dx = phy reg addr |
; ax = data |
align 4 |
mdio_read: |
DEBUGF 1,"MDIO read\n" |
shl ecx, 21 ; PHY addr |
shl edx, 16 ; PHY reg addr |
mov eax, ecx |
or eax, edx |
or eax, 10b shl 26 ; read opcode |
set_io 0 |
set_io reg_mdi_ctrl |
out dx, eax |
.wait: |
delay |
in eax, dx |
test eax, 1 shl 28 ; ready bit |
jz .wait |
ret |
; ax = data |
; cx = phy addr |
; dx = phy reg addr |
; ax = data |
align 4 |
mdio_write: |
DEBUGF 1,"MDIO write\n" |
and eax, 0xffff |
shl ecx, 21 ; PHY addr |
shl edx, 16 ; PHY reg addr |
or eax, ecx |
or eax, edx |
or eax, 01b shl 26 ; write opcode |
set_io 0 |
set_io reg_mdi_ctrl |
out dx, eax |
.wait: |
delay |
in eax, dx |
test eax, 1 shl 28 ; ready bit |
jz .wait |
ret |
read_mac: |
ret |
align 4 |
MAC_read_eeprom: |
mov esi, 0 |
call ee_read |
mov word[device.mac], si |
mov esi, 1 |
call ee_read |
mov word[device.mac+2], si |
mov esi, 2 |
call ee_read |
mov word[device.mac+4], si |
ret |
align 4 |
MAC_write: |
;;;; |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 ; number of currently running devices |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'i8255x', 0 ; max 16 chars include zero |
devicename db 'Intel Etherexpress pro/100', 0 |
confcmd_data db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1 |
db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2 |
db 0x80, 0x3f, 0x05 ; 22 bytes total |
device_id_list: |
dw 0x1029 |
dw 0x1030 |
dw 0x1031 |
dw 0x1032 |
dw 0x1033 |
dw 0x1034 |
dw 0x1038 |
dw 0x1039 |
dw 0x103A |
dw 0x103B |
dw 0x103C |
dw 0x103D |
dw 0x103E |
dw 0x1050 |
dw 0x1051 |
dw 0x1052 |
dw 0x1053 |
dw 0x1054 |
dw 0x1055 |
dw 0x1056 |
dw 0x1057 |
dw 0x1059 |
dw 0x1064 |
dw 0x1065 |
dw 0x1066 |
dw 0x1067 |
dw 0x1068 |
dw 0x1069 |
dw 0x106A |
dw 0x106B |
dw 0x1091 |
dw 0x1092 |
dw 0x1093 |
dw 0x1094 |
dw 0x1095 |
dw 0x10fe |
dw 0x1209 |
dw 0x1229 |
dw 0x2449 |
dw 0x2459 |
dw 0x245D |
dw 0x27DC |
DEVICE_IDs = ($ - device_id_list) / 2 |
mac_82557_D100_A = 0 |
mac_82557_D100_B = 1 |
mac_82557_D100_C = 2 |
mac_82558_D101_A4 = 4 |
mac_82558_D101_B0 = 5 |
mac_82559_D101M = 8 |
mac_82559_D101S = 9 |
mac_82550_D102 = 12 |
mac_82550_D102_C = 13 |
mac_82551_E = 14 |
mac_82551_F = 15 |
mac_82551_10 = 16 |
mac_unknown = 0xFF |
phy_100a = 0x000003E0 |
phy_100c = 0x035002A8 |
phy_82555_tx = 0x015002A8 |
phy_nsc_tx = 0x5C002000 |
phy_82562_et = 0x033002A8 |
phy_82562_em = 0x032002A8 |
phy_82562_ek = 0x031002A8 |
phy_82562_eh = 0x017002A8 |
phy_82552_v = 0xd061004d |
phy_unknown = 0xFFFFFFFF |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/imports.inc |
---|
0,0 → 1,102 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
macro kernel_export [name]{ |
forward |
if used name |
if DEBUG |
display 'uses: ',`name,#13,#10 |
end if |
extrn name |
end if |
} |
; all exported kernel functions and data |
kernel_export \ |
RegService,\ |
GetService,\ |
ServiceHandler,\ |
AttachIntHandler,\ |
GetIntHandler,\ |
FpuSave,\ |
FpuRestore,\ |
ReservePortArea,\ |
Boot_Log,\ |
\ |
MutexInit,\ |
MutexLock,\ |
MutexUnlock,\ |
\ |
PciApi,\ |
PciRead32,\ |
PciRead16,\ |
PciRead8,\ |
PciWrite8,\ |
PciWrite16,\ |
PciWrite32,\ |
\ |
AllocPage,\ |
AllocPages,\ |
FreePage,\ |
MapPage,\ |
MapSpace,\ |
MapIoMem,\ |
GetPgAddr,\ |
CommitPages,\ |
ReleasePages,\ |
\ |
AllocKernelSpace,\ |
FreeKernelSpace,\ |
KernelAlloc,\ |
KernelFree,\ |
UserAlloc,\ |
UserFree,\ |
Kmalloc,\ |
Kfree,\ |
CreateRingBuffer,\ |
\ |
GetPid,\ |
CreateObject,\ |
DestroyObject,\ |
CreateEvent,\ |
RaiseEvent,\ |
WaitEvent,\ |
DestroyEvent,\ |
ClearEvent,\ |
\ |
LoadCursor,\ |
SelectHwCursor,\ |
SetHwCursor,\ |
HwCursorRestore,\ |
HwCursorCreate,\ |
\ |
SysMsgBoardStr,\ |
SysMsgBoardChar,\ |
GetCurrentTask,\ |
LoadFile,\ |
SendEvent,\ |
SetMouseData,\ |
Sleep,\ |
GetTimerTicks,\ |
\ |
strncat,\ |
strncpy,\ |
strncmp,\ |
strnlen,\ |
strchr,\ |
strrchr,\ |
\ |
LFBAddress,\ |
GetDisplay,\ |
SetScreen,\ |
\ |
NetRegDev,\ |
NetUnRegDev,\ |
NetPtrToNum,\ |
NetLinkChanged,\ |
Eth_input,\ |
IPv4_input |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/mtd80x.asm |
---|
0,0 → 1,1258 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; MTD80x driver for KolibriOS ;; |
;; ;; |
;; Based on mtd80x.c from the etherboot project ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
NUM_TX_DESC = 4 |
NUM_RX_DESC = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
; for different PHY |
MysonPHY = 1 |
AhdocPHY = 2 |
SeeqPHY = 3 |
MarvellPHY = 4 |
Myson981 = 5 |
LevelOnePHY = 6 |
OtherPHY = 10 |
; Offsets to the Command and Status Registers. |
PAR0 = 0x0 ; physical address 0-3 |
PAR1 = 0x04 ; physical address 4-5 |
MAR0 = 0x08 ; multicast address 0-3 |
MAR1 = 0x0C ; multicast address 4-7 |
FAR0 = 0x10 ; flow-control address 0-3 |
FAR1 = 0x14 ; flow-control address 4-5 |
TCRRCR = 0x18 ; receive & transmit configuration |
BCR = 0x1C ; bus command |
TXPDR = 0x20 ; transmit polling demand |
RXPDR = 0x24 ; receive polling demand |
RXCWP = 0x28 ; receive current word pointer |
TXLBA = 0x2C ; transmit list base address |
RXLBA = 0x30 ; receive list base address |
ISR = 0x34 ; interrupt status |
IMR = 0x38 ; interrupt mask |
FTH = 0x3C ; flow control high/low threshold |
MANAGEMENT = 0x40 ; bootrom/eeprom and mii management |
TALLY = 0x44 ; tally counters for crc and mpa |
TSR = 0x48 ; tally counter for transmit status |
BMCRSR = 0x4c ; basic mode control and status |
PHYIDENTIFIER = 0x50 ; phy identifier |
ANARANLPAR = 0x54 ; auto-negotiation advertisement and link partner ability |
ANEROCR = 0x58 ; auto-negotiation expansion and pci conf. |
BPREMRPSR = 0x5c ; bypass & receive error mask and phy status |
; Bits in the interrupt status/enable registers. |
RFCON = 0x00020000 ; receive flow control xon packet |
RFCOFF = 0x00010000 ; receive flow control xoff packet |
LSCStatus = 0x00008000 ; link status change |
ANCStatus = 0x00004000 ; autonegotiation completed |
FBE = 0x00002000 ; fatal bus error |
FBEMask = 0x00001800 ; mask bit12-11 |
ParityErr = 0x00000000 ; parity error |
TargetErr = 0x00001000 ; target abort |
MasterErr = 0x00000800 ; master error |
TUNF = 0x00000400 ; transmit underflow |
ROVF = 0x00000200 ; receive overflow |
ETI = 0x00000100 ; transmit early int |
ERI = 0x00000080 ; receive early int |
CNTOVF = 0x00000040 ; counter overflow |
RBU = 0x00000020 ; receive buffer unavailable |
TBU = 0x00000010 ; transmit buffer unavilable |
TI = 0x00000008 ; transmit interrupt |
RI = 0x00000004 ; receive interrupt |
RxErr = 0x00000002 ; receive error |
; Bits in the NetworkConfig register. |
RxModeMask = 0xe0 |
AcceptAllPhys = 0x80 ; promiscuous mode |
AcceptBroadcast = 0x40 ; accept broadcast |
AcceptMulticast = 0x20 ; accept mutlicast |
AcceptRunt = 0x08 ; receive runt pkt |
ALP = 0x04 ; receive long pkt |
AcceptErr = 0x02 ; receive error pkt |
AcceptMyPhys = 0x00000000 |
RxEnable = 0x00000001 |
RxFlowCtrl = 0x00002000 |
TxEnable = 0x00040000 |
TxModeFDX = 0x00100000 |
TxThreshold = 0x00e00000 |
PS1000 = 0x00010000 |
PS10 = 0x00080000 |
FD = 0x00100000 |
; Bits in network_desc.status |
RXOWN = 0x80000000 ; own bit |
FLNGMASK = 0x0fff0000 ; frame length |
FLNGShift = 16 |
MARSTATUS = 0x00004000 ; multicast address received |
BARSTATUS = 0x00002000 ; broadcast address received |
PHYSTATUS = 0x00001000 ; physical address received |
RXFSD = 0x00000800 ; first descriptor |
RXLSD = 0x00000400 ; last descriptor |
ErrorSummary = 0x80 ; error summary |
RUNT = 0x40 ; runt packet received |
LONG = 0x20 ; long packet received |
FAE = 0x10 ; frame align error |
CRC = 0x08 ; crc error |
RXER = 0x04 ; receive error |
; rx_desc_control_bits |
RXIC = 0x00800000 ; interrupt control |
RBSShift = 0 |
; tx_desc_status_bits |
TXOWN = 0x80000000 ; own bit |
JABTO = 0x00004000 ; jabber timeout |
CSL = 0x00002000 ; carrier sense lost |
LC = 0x00001000 ; late collision |
EC = 0x00000800 ; excessive collision |
UDF = 0x00000400 ; fifo underflow |
DFR = 0x00000200 ; deferred |
HF = 0x00000100 ; heartbeat fail |
NCRMask = 0x000000ff ; collision retry count |
NCRShift = 0 |
; tx_desc_control_bits |
TXIC = 0x80000000 ; interrupt control |
ETIControl = 0x40000000 ; early transmit interrupt |
TXLD = 0x20000000 ; last descriptor |
TXFD = 0x10000000 ; first descriptor |
CRCEnable = 0x08000000 ; crc control |
PADEnable = 0x04000000 ; padding control |
RetryTxLC = 0x02000000 ; retry late collision |
PKTSMask = 0x3ff800 ; packet size bit21-11 |
PKTSShift = 11 |
TBSMask = 0x000007ff ; transmit buffer bit 10-0 |
TBSShift = 0 |
; BootROM/EEPROM/MII Management Register |
MASK_MIIR_MII_READ = 0x00000000 |
MASK_MIIR_MII_WRITE = 0x00000008 |
MASK_MIIR_MII_MDO = 0x00000004 |
MASK_MIIR_MII_MDI = 0x00000002 |
MASK_MIIR_MII_MDC = 0x00000001 |
; ST+OP+PHYAD+REGAD+TA |
OP_READ = 0x6000 ; ST:01+OP:10+PHYAD+REGAD+TA:Z0 |
OP_WRITE = 0x5002 ; ST:01+OP:01+PHYAD+REGAD+TA:10 |
; ------------------------------------------------------------------------- |
; Constants for Myson PHY |
; ------------------------------------------------------------------------- |
MysonPHYID = 0xd0000302 |
MysonPHYID0 = 0x0302 |
StatusRegister = 18 |
SPEED100 = 0x0400 ; bit10 |
FULLMODE = 0x0800 ; bit11 |
; ------------------------------------------------------------------------- |
; Constants for Seeq 80225 PHY |
; ------------------------------------------------------------------------- |
SeeqPHYID0 = 0x0016 |
MIIRegister18 = 18 |
SPD_DET_100 = 0x80 |
DPLX_DET_FULL = 0x40 |
; ------------------------------------------------------------------------- |
; Constants for Ahdoc 101 PHY |
; ------------------------------------------------------------------------- |
AhdocPHYID0 = 0x0022 |
DiagnosticReg = 18 |
DPLX_FULL = 0x0800 |
Speed_100 = 0x0400 |
; -------------------------------------------------------------------------- |
; Constants |
; -------------------------------------------------------------------------- |
MarvellPHYID0 = 0x0141 |
LevelOnePHYID0 = 0x0013 |
MII1000BaseTControlReg = 9 |
MII1000BaseTStatusReg = 10 |
SpecificReg = 17 |
; for 1000BaseT Control Register |
PHYAbletoPerform1000FullDuplex = 0x0200 |
PHYAbletoPerform1000HalfDuplex = 0x0100 |
PHY1000AbilityMask = 0x300 |
; for phy specific status register, marvell phy. |
SpeedMask = 0x0c000 |
Speed_1000M = 0x08000 |
Speed_100M = 0x4000 |
Speed_10M = 0 |
Full_Duplex = 0x2000 |
; for phy specific status register, levelone phy |
LXT1000_100M = 0x08000 |
LXT1000_1000M = 0x0c000 |
LXT1000_Full = 0x200 |
; for PHY |
LinkIsUp = 0x0004 |
LinkIsUp2 = 0x00040000 |
virtual at 0 |
mtd_desc: |
.status dd ? |
.control dd ? |
.buffer dd ? |
.next_desc dd ? |
.next_desc_logical dd ? |
.skbuff dd ? |
.reserved1 dd ? |
.reserved2 dd ? |
.size = $ |
end virtual |
virtual at ebx |
device: |
ETH_DEVICE |
.tx_desc rb NUM_TX_DESC*mtd_desc.size |
.rx_desc rb NUM_RX_DESC*mtd_desc.size |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.dev_id dw ? |
.flags dd ? |
.crvalue dd ? |
.bcrvalue dd ? |
.cur_rx dd ? |
.cur_tx dd ? |
; These values are keep track of the transceiver/media in use. |
.linkok dd ? |
.line_speed dd ? |
.duplexmode dd ? |
.default_port dd ? |
.PHYType dd ? |
; MII transceiver section. |
.mii_cnt dd ? ; MII device addresses. |
.phys db ? ; MII device addresses. |
device_size = $ - device |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device_size, .fail |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 |
; Ok, the eth_device structure is ready, let's probe the device |
; Because initialization fires IRQ, IRQ handler must be aware of this device |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
call probe ; this function will output in eax |
test eax, eax |
jnz .err2 ; If an error occured, exit |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 2,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err2: |
dec [devices] |
.err: |
DEBUGF 2,"removing device structure\n" |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; /* Disable Tx Rx*/ |
; outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); |
; |
; /* Reset the chip to erase previous misconfiguration. */ |
; mtd_reset(nic); |
; - Detach int handler |
; - Remove device from local list (device_list) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
;------- |
; |
; PROBE |
; |
;------- |
align 4 |
probe: |
DEBUGF 2,"Probing mtd80x device\n" |
PCI_make_bus_master |
stdcall PciRead32, [device.pci_bus], [device.pci_dev], 0 |
cmp ax, 0x1516 |
jne .notfound |
shr eax, 16 |
mov [device.dev_id], ax |
cmp ax, 0x0800 |
je .has_mii_xcvr |
cmp ax, 0x0803 |
je .has_chip_xcvr |
cmp ax, 0x0891 |
je .has_mii_xcvr |
.notfound: |
DEBUGF 1,"Device not supported!\n" |
xor eax, eax |
dec eax |
ret |
.has_chip_xcvr: |
DEBUGF 1,"Device has chip xcvr\n" |
jmp .xcvr_set |
.has_mii_xcvr: |
DEBUGF 1,"Device has mii xcvr\n" |
.xcvr_set: |
call read_mac |
; Reset the chip to erase previous misconfiguration. |
set_io 0 |
set_io BCR |
xor eax, eax |
inc eax |
out dx, eax |
; find the connected MII xcvrs |
cmp [device.dev_id], 0x0803 |
je .is_803 |
; int phy, phy_idx = 0; |
; |
; for (phy = 1; phy < 32 && phy_idx < 1; phy++) { |
; int mii_status = mdio_read(nic, phy, 1); |
; |
; if (mii_status != 0xffff && mii_status != 0x0000) { |
; mtdx.phys[phy_idx] = phy; |
; |
; DBG ( "%s: MII PHY found at address %d, status " |
; "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); |
; /* get phy type */ |
; { |
; unsigned int data; |
; |
; data = mdio_read(nic, mtdx.phys[phy_idx], 2); |
; if (data equ= SeeqPHYID0) |
; mtdx.PHYType = SeeqPHY; |
; else if (data equ= AhdocPHYID0) |
; mtdx.PHYType = AhdocPHY; |
; else if (data equ= MarvellPHYID0) |
; mtdx.PHYType = MarvellPHY; |
; else if (data equ= MysonPHYID0) |
; mtdx.PHYType = Myson981; |
; else if (data equ= LevelOnePHYID0) |
; mtdx.PHYType = LevelOnePHY; |
; else |
; mtdx.PHYType = OtherPHY; |
; } |
; phy_idx++; |
; } |
; } |
; |
; mtdx.mii_cnt = phy_idx; |
; if (phy_idx equ= 0) { |
; printf("%s: MII PHY not found -- this device may " |
; "not operate correctly.\n", mtdx.nic_name); |
; } |
jmp .no_803 |
.is_803: |
mov [device.phys], 32 |
; get phy type |
set_io 0 |
set_io PHYIDENTIFIER |
in eax, dx |
cmp eax, MysonPHYID |
jne @f |
mov [device.PHYType], MysonPHY |
DEBUGF 1,"MysonPHY\n" |
jmp .no_803 |
@@: |
mov [device.PHYType], OtherPHY |
DEBUGF 1,"OtherPHY\n" |
.no_803: |
;------- |
; |
; RESET |
; |
;------- |
align 4 |
reset: |
DEBUGF 1,"Resetting mtd80x\n" |
;-------------------------------- |
; insert irq handler on given irq |
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
; Reset the chip to erase previous misconfiguration. |
set_io 0 |
set_io BCR |
xor eax, eax |
inc eax |
out dx, eax |
call init_ring |
; Initialize other registers. |
; Configure the PCI bus bursts and FIFO thresholds. |
mov [device.bcrvalue], 0x10 ; little-endian, 8 burst length |
mov [device.crvalue], 0xa00 ; 128 burst length |
cmp [device.dev_id], 0x891 |
jne @f |
or [device.bcrvalue], 0x200 ; set PROG bit |
or [device.crvalue], 0x02000000 ; set enhanced bit |
@@: |
or [device.crvalue], RxEnable + TxThreshold + TxEnable |
call set_rx_mode |
set_io 0 |
set_io BCR |
mov eax, [device.bcrvalue] |
out dx, eax |
set_io TCRRCR |
mov eax, [device.crvalue] |
out dx, eax |
call getlinkstatus |
call getlinktype |
; Restart Rx engine if stopped. |
set_io 0 |
set_io RXPDR |
xor eax, eax |
out dx, eax |
; Enable interrupts |
set_io 0 |
set_io ISR |
mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) |
out dx, eax |
set_io IMR |
; mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) |
out dx, eax |
; clear packet/byte counters |
xor eax, eax |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
xor eax, eax |
ret |
align 4 |
init_ring: |
DEBUGF 1,"initializing rx and tx ring\n" |
; Initialize all Rx descriptors |
lea esi, [device.rx_desc] |
mov [device.cur_rx], esi |
mov ecx, NUM_RX_DESC |
.rx_desc_loop: |
mov [esi + mtd_desc.status], RXOWN |
mov [esi + mtd_desc.control], 1536 shl RBSShift |
lea eax, [esi + mtd_desc.size] |
mov [esi + mtd_desc.next_desc_logical], eax |
push ecx esi |
GetRealAddr |
mov [esi + mtd_desc.next_desc], eax |
stdcall KernelAlloc, 1536 |
pop esi |
push esi |
mov [esi + mtd_desc.skbuff], eax |
call GetPgAddr |
pop esi ecx |
mov [esi + mtd_desc.buffer], eax |
add esi, mtd_desc.size |
loop .rx_desc_loop |
; Mark the last entry as wrapping the ring. |
lea eax, [device.rx_desc] |
mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax |
push esi |
GetRealAddr |
pop esi |
mov [esi - mtd_desc.size + mtd_desc.next_desc], eax |
set_io 0 |
set_io RXLBA |
out dx, eax |
; Initialize all Tx descriptors |
lea esi, [device.tx_desc] |
mov [device.cur_tx], esi |
mov ecx, NUM_TX_DESC |
.tx_desc_loop: |
mov [esi + mtd_desc.status], 0 |
lea eax, [esi + mtd_desc.size] |
mov [esi + mtd_desc.next_desc_logical], eax |
push ecx esi |
GetRealAddr |
pop esi ecx |
mov [esi + mtd_desc.next_desc], eax |
add esi, mtd_desc.size |
loop .tx_desc_loop |
; Mark the last entry as wrapping the ring. |
lea eax, [device.tx_desc] |
mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax |
push esi |
GetRealAddr |
pop esi |
mov [esi - mtd_desc.size + mtd_desc.next_desc], eax |
set_io 0 |
set_io TXLBA |
out dx, eax |
ret |
align 4 |
set_rx_mode: |
DEBUGF 1,"Setting RX mode\n" |
; Too many to match, or accept all multicasts. |
set_io 0 |
set_io MAR0 |
xor eax, eax |
not eax |
out dx, eax |
set_io MAR1 |
out dx, eax |
and [device.crvalue], not (RxModeMask) |
or [device.crvalue], AcceptBroadcast + AcceptMulticast + AcceptMyPhys |
ret |
align 4 |
getlinkstatus: |
DEBUGF 1,"Getting link status\n" |
mov [device.linkok], 0 |
cmp [device.PHYType], MysonPHY |
jne .no_myson_phy |
set_io 0 |
set_io BMCRSR |
mov ecx, 1000 |
.loop1: |
in eax, dx |
test eax, LinkIsUp2 |
jnz .link_ok |
push ecx edx ebx |
mov esi, 10 |
call Sleep |
pop ebx edx ecx |
loop .loop1 |
ret |
.no_myson_phy: |
; for (i = 0; i < DelayTime; ++i) { |
; if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { |
; mtdx.linkok = 1; |
; return; |
; } |
; m80x_delay(100); |
ret |
.link_ok: |
DEBUGF 1,"Link is up\n" |
inc [device.linkok] |
ret |
align 4 |
getlinktype: |
DEBUGF 1,"Getting link type\n" |
cmp [device.PHYType], MysonPHY |
jne .no_myson_phy |
DEBUGF 1,"myson PHY\n" |
set_io 0 |
set_io TCRRCR |
in eax, dx |
mov [device.duplexmode], 1 ; 1 = half duplex |
test eax, FD |
jne @f |
DEBUGF 1,"full duplex\n" |
inc [device.duplexmode] ; 2 = full duplex |
@@: |
mov [device.line_speed], 1 ; 1 = 10M |
test eax, PS10 |
jne @f |
DEBUGF 1,"100mbit\n" |
inc [device.line_speed] ; 2 = 100M |
@@: |
ret |
.no_myson_phy: |
DEBUGF 1,"no myson phy\n" |
; if (mtdx.PHYType equ= SeeqPHY) { /* this PHY is SEEQ 80225 */ |
; unsigned int data; |
; |
; data = mdio_read(dev, mtdx.phys[0], MIIRegister18); |
; if (data & SPD_DET_100) |
; mtdx.line_speed = 2; /* 100M */ |
; else |
; mtdx.line_speed = 1; /* 10M */ |
; if (data & DPLX_DET_FULL) |
; mtdx.duplexmode = 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode = 1; /* half duplex mode */ |
; } else if (mtdx.PHYType equ= AhdocPHY) { |
; unsigned int data; |
; |
; data = mdio_read(dev, mtdx.phys[0], DiagnosticReg); |
; if (data & Speed_100) |
; mtdx.line_speed = 2; /* 100M */ |
; else |
; mtdx.line_speed = 1; /* 10M */ |
; if (data & DPLX_FULL) |
; mtdx.duplexmode = 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode = 1; /* half duplex mode */ |
; } |
; else if (mtdx.PHYType equ= MarvellPHY) { |
; unsigned int data; |
; |
; data = mdio_read(dev, mtdx.phys[0], SpecificReg); |
; if (data & Full_Duplex) |
; mtdx.duplexmode = 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode = 1; /* half duplex mode */ |
; data &= SpeedMask; |
; if (data equ= Speed_1000M) |
; mtdx.line_speed = 3; /* 1000M */ |
; else if (data equ= Speed_100M) |
; mtdx.line_speed = 2; /* 100M */ |
; else |
; mtdx.line_speed = 1; /* 10M */ |
; } |
; else if (mtdx.PHYType equ= Myson981) { |
; unsigned int data; |
; |
; data = mdio_read(dev, mtdx.phys[0], StatusRegister); |
; |
; if (data & SPEED100) |
; mtdx.line_speed = 2; |
; else |
; mtdx.line_speed = 1; |
; |
; if (data & FULLMODE) |
; mtdx.duplexmode = 2; |
; else |
; mtdx.duplexmode = 1; |
; } |
; else if (mtdx.PHYType equ= LevelOnePHY) { |
; unsigned int data; |
; |
; data = mdio_read(dev, mtdx.phys[0], SpecificReg); |
; if (data & LXT1000_Full) |
; mtdx.duplexmode = 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode = 1; /* half duplex mode */ |
; data &= SpeedMask; |
; if (data equ= LXT1000_1000M) |
; mtdx.line_speed = 3; /* 1000M */ |
; else if (data equ= LXT1000_100M) |
; mtdx.line_speed = 2; /* 100M */ |
; else |
; mtdx.line_speed = 1; /* 10M */ |
; } |
; // chage crvalue |
; // mtdx.crvalue&equ(~PS10)&(~FD); |
; mtdx.crvalue &= (~PS10) & (~FD) & (~PS1000); |
; if (mtdx.line_speed equ= 1) |
; mtdx.crvalue |= PS10; |
; else if (mtdx.line_speed equ= 3) |
; mtdx.crvalue |= PS1000; |
; if (mtdx.duplexmode equ= 2) |
; mtdx.crvalue |= FD; |
; |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], 1514 |
ja .fail |
mov esi, [device.cur_tx] |
push [esi + mtd_desc.next_desc_logical] |
pop [device.cur_tx] |
; todo: check if descriptor is not owned by the device! |
mov eax, [esp + 4] |
mov [esi + mtd_desc.skbuff], eax |
GetRealAddr |
mov [esi + mtd_desc.buffer], eax |
mov eax, [esp + 8] |
shl eax, PKTSShift ; packet size |
or eax, TXLD + TXFD + CRCEnable + PADEnable + TXIC + 1536 shl TBSShift ; buffer size |
mov [esi + mtd_desc.control], eax |
mov [esi + mtd_desc.status], TXOWN |
;------------- |
; Update stats |
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
; Point to transmit descriptor |
set_io 0 |
set_io TXLBA |
mov eax, esi |
GetRealAddr |
out dx, eax |
; set_io TCRRCR |
; mov eax, [device.crvalue] |
; out dx, eax |
; Wake the potentially-idle transmit channel. |
set_io TXPDR ; TX Poll |
xor eax, eax |
out dx, eax |
DEBUGF 1,"transmit ok\n" |
xor eax, eax |
ret 8 |
.fail: |
DEBUGF 1,"transmit failed\n" |
or eax, -1 |
stdcall KernelFree, [esp + 4] |
ret 8 |
align 4 |
read_mac: |
set_io 0 |
set_io PAR0 |
lea edi, [device.mac] |
insd |
stosd |
set_io PAR1 |
insw |
stosw |
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
ret |
align 4 |
write_mac: |
ret |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io ISR |
in eax, dx |
out dx, eax ; send it back to ACK |
test eax, eax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, ax |
test ax, RI ; receive interrupt |
jz .no_rx |
DEBUGF 1,"Receive interrupt\n" |
.rx: |
push ax |
.rx_loop: |
mov esi, [device.cur_rx] |
test [esi + mtd_desc.status], RXOWN |
jnz .fail_rx |
push .rx_complete |
mov ecx, [esi + mtd_desc.status] |
shr ecx, FLNGShift |
sub ecx, 4 ; we dont need CRC |
push ecx |
;------------- |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
push [esi + mtd_desc.skbuff] |
jmp Eth_input |
.rx_complete: |
mov esi, [device.cur_rx] |
mov [esi + mtd_desc.control], 1536 shl RBSShift |
stdcall KernelAlloc, 1536 |
mov [esi + mtd_desc.skbuff], eax |
call GetPgAddr |
mov [esi + mtd_desc.buffer], eax |
mov [esi + mtd_desc.status], RXOWN |
mov eax, [esi + mtd_desc.next_desc_logical] |
mov [device.cur_rx], eax |
jmp .rx_loop |
; |
; while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) |
; { |
; mtdx.cur_rx->status = RXOWN; |
; mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; |
; } |
; |
; /* Restart Rx engine if stopped. */ |
; outl(0, mtdx.ioaddr + RXPDR); |
.fail_rx: |
DEBUGF 1,"RX failed\n" |
pop ax |
.no_rx: |
test ax, TI ; transmit interrupt |
jz .no_tx |
DEBUGF 1,"Transmit interrupt\n" |
push ax |
lea esi, [device.tx_desc] |
mov ecx, NUM_TX_DESC |
.tx_loop: |
test [esi + mtd_desc.status], TXOWN |
jnz .skip_this_one |
mov eax, [esi + mtd_desc.skbuff] |
test eax, eax |
je .skip_this_one |
mov [esi + mtd_desc.skbuff], 0 |
DEBUGF 1,"freeing buffer:%x\n", eax |
stdcall KernelFree, eax |
.skip_this_one: |
mov esi, [esi + mtd_desc.next_desc_logical] |
loop .tx_loop |
pop ax |
.no_tx: |
test ax, TBU |
jz .no_tbu |
DEBUGF 1,"Transmit buffer unavailable!\n" |
.no_tbu: |
.fail: |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'mtd80x',0 ; max 16 chars include zero |
; 0x1516, 0x0800, "MTD800", "Myson MTD800" |
; 0x1516, 0x0803, "MTD803", "Surecom EP-320X" |
; 0x1516, 0x0891, "MTD891", "Myson MTD891" |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16 ; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/rhine.asm |
---|
0,0 → 1,1670 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2010-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; rhine.asm ;; |
;; ;; |
;; Ethernet driver for Kolibri OS ;; |
;; ;; |
;; This driver is based on the via-rhine driver from ;; |
;; the etherboot 5.0.6 project. The copyright statement is ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; Rewritten in flat assembler by Asper (asper.85@mail.ru) ;; |
;; and hidnplayr (hidnplayr@gmail.com) ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
TX_RING_SIZE = 4 |
RX_RING_SIZE = 4 |
; max time out delay time |
W_MAX_TIMEOUT = 0x0FFF |
; Size of the in-memory receive ring. |
RX_BUF_LEN_IDX = 3 ; 0==8K, 1==16K, 2==32K, 3==64K |
RX_BUF_LEN = (8192 shl RX_BUF_LEN_IDX) |
; PCI Tuning Parameters |
; Threshold is bytes transferred to chip before transmission starts. |
TX_FIFO_THRESH = 256 ; In bytes, rounded down to 32 byte units. |
; The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024. |
RX_FIFO_THRESH = 4 ; Rx buffer level before first PCI xfer. |
RX_DMA_BURST = 4 ; Maximum PCI burst, '4' is 256 bytes |
TX_DMA_BURST = 4 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public service_proc |
public version |
;************************************************************************** |
; VIA Rhine Register Definitions |
;************************************************************************** |
byPAR0 = 0x00 |
byRCR = 0x06 |
byTCR = 0x07 |
byCR0 = 0x08 |
byCR1 = 0x09 |
byISR0 = 0x0c |
byISR1 = 0x0d |
byIMR0 = 0x0e |
byIMR1 = 0x0f |
byMAR0 = 0x10 |
byMAR1 = 0x11 |
byMAR2 = 0x12 |
byMAR3 = 0x13 |
byMAR4 = 0x14 |
byMAR5 = 0x15 |
byMAR6 = 0x16 |
byMAR7 = 0x17 |
dwCurrentRxDescAddr = 0x18 |
dwCurrentTxDescAddr = 0x1c |
dwCurrentRDSE0 = 0x20 |
dwCurrentRDSE1 = 0x24 |
dwCurrentRDSE2 = 0x28 |
dwCurrentRDSE3 = 0x2c |
dwNextRDSE0 = 0x30 |
dwNextRDSE1 = 0x34 |
dwNextRDSE2 = 0x38 |
dwNextRDSE3 = 0x3c |
dwCurrentTDSE0 = 0x40 |
dwCurrentTDSE1 = 0x44 |
dwCurrentTDSE2 = 0x48 |
dwCurrentTDSE3 = 0x4c |
dwNextTDSE0 = 0x50 |
dwNextTDSE1 = 0x54 |
dwNextTDSE2 = 0x58 |
dwNextTDSE3 = 0x5c |
dwCurrRxDMAPtr = 0x60 |
dwCurrTxDMAPtr = 0x64 |
byMPHY = 0x6c |
byMIISR = 0x6d |
byBCR0 = 0x6e |
byBCR1 = 0x6f |
byMIICR = 0x70 |
byMIIAD = 0x71 |
wMIIDATA = 0x72 |
byEECSR = 0x74 |
byTEST = 0x75 |
byGPIO = 0x76 |
byCFGA = 0x78 |
byCFGB = 0x79 |
byCFGC = 0x7a |
byCFGD = 0x7b |
wTallyCntMPA = 0x7c |
wTallyCntCRC = 0x7d |
bySTICKHW = 0x83 |
byWOLcrClr = 0xA4 |
byWOLcgClr = 0xA7 |
byPwrcsrClr = 0xAC |
;--------------------- Exioaddr Definitions ------------------------- |
; Bits in the RCR register |
RCR_RRFT2 = 0x80 |
RCR_RRFT1 = 0x40 |
RCR_RRFT0 = 0x20 |
RCR_PROM = 0x10 |
RCR_AB = 0x08 |
RCR_AM = 0x04 |
RCR_AR = 0x02 |
RCR_SEP = 0x01 |
; Bits in the TCR register |
TCR_RTSF = 0x80 |
TCR_RTFT1 = 0x40 |
TCR_RTFT0 = 0x20 |
TCR_OFSET = 0x08 |
TCR_LB1 = 0x04 ; loopback[1] |
TCR_LB0 = 0x02 ; loopback[0] |
; Bits in the CR0 register |
CR0_RDMD = 0x40 ; rx descriptor polling demand |
CR0_TDMD = 0x20 ; tx descriptor polling demand |
CR0_TXON = 0x10 |
CR0_RXON = 0x08 |
CR0_STOP = 0x04 ; stop NIC, default = 1 |
CR0_STRT = 0x02 ; start NIC |
CR0_INIT = 0x01 ; start init process |
; Bits in the CR1 register |
CR1_SFRST = 0x80 ; software reset |
CR1_RDMD1 = 0x40 ; RDMD1 |
CR1_TDMD1 = 0x20 ; TDMD1 |
CR1_KEYPAG = 0x10 ; turn on par/key |
CR1_DPOLL = 0x08 ; disable rx/tx auto polling |
CR1_FDX = 0x04 ; full duplex mode |
CR1_ETEN = 0x02 ; early tx mode |
CR1_EREN = 0x01 ; early rx mode |
; Bits in the CR register |
CR_RDMD = 0x0040 ; rx descriptor polling demand |
CR_TDMD = 0x0020 ; tx descriptor polling demand |
CR_TXON = 0x0010 |
CR_RXON = 0x0008 |
CR_STOP = 0x0004 ; stop NIC, default = 1 |
CR_STRT = 0x0002 ; start NIC |
CR_INIT = 0x0001 ; start init process |
CR_SFRST = 0x8000 ; software reset |
CR_RDMD1 = 0x4000 ; RDMD1 |
CR_TDMD1 = 0x2000 ; TDMD1 |
CR_KEYPAG = 0x1000 ; turn on par/key |
CR_DPOLL = 0x0800 ; disable rx/tx auto polling |
CR_FDX = 0x0400 ; full duplex mode |
CR_ETEN = 0x0200 ; early tx mode |
CR_EREN = 0x0100 ; early rx mode |
; Bits in the IMR0 register |
IMR0_CNTM = 0x80 |
IMR0_BEM = 0x40 |
IMR0_RUM = 0x20 |
IMR0_TUM = 0x10 |
IMR0_TXEM = 0x08 |
IMR0_RXEM = 0x04 |
IMR0_PTXM = 0x02 |
IMR0_PRXM = 0x01 |
; define imrshadow |
IMRShadow = 0x5AFF |
; Bits in the IMR1 register |
IMR1_INITM = 0x80 |
IMR1_SRCM = 0x40 |
IMR1_NBFM = 0x10 |
IMR1_PRAIM = 0x08 |
IMR1_RES0M = 0x04 |
IMR1_ETM = 0x02 |
IMR1_ERM = 0x01 |
; Bits in the ISR register |
ISR_INITI = 0x8000 |
ISR_SRCI = 0x4000 |
ISR_ABTI = 0x2000 |
ISR_NORBF = 0x1000 |
ISR_PKTRA = 0x0800 |
ISR_RES0 = 0x0400 |
ISR_ETI = 0x0200 |
ISR_ERI = 0x0100 |
ISR_CNT = 0x0080 |
ISR_BE = 0x0040 |
ISR_RU = 0x0020 |
ISR_TU = 0x0010 |
ISR_TXE = 0x0008 |
ISR_RXE = 0x0004 |
ISR_PTX = 0x0002 |
ISR_PRX = 0x0001 |
; Bits in the ISR0 register |
ISR0_CNT = 0x80 |
ISR0_BE = 0x40 |
ISR0_RU = 0x20 |
ISR0_TU = 0x10 |
ISR0_TXE = 0x08 |
ISR0_RXE = 0x04 |
ISR0_PTX = 0x02 |
ISR0_PRX = 0x01 |
; Bits in the ISR1 register |
ISR1_INITI = 0x80 |
ISR1_SRCI = 0x40 |
ISR1_NORBF = 0x10 |
ISR1_PKTRA = 0x08 |
ISR1_ETI = 0x02 |
ISR1_ERI = 0x01 |
; ISR ABNORMAL CONDITION |
ISR_ABNORMAL = ISR_BE+ISR_RU+ISR_TU+ISR_CNT+ISR_NORBF+ISR_PKTRA |
; Bits in the MIISR register |
MIISR_MIIERR = 0x08 |
MIISR_MRERR = 0x04 |
MIISR_LNKFL = 0x02 |
MIISR_SPEED = 0x01 |
; Bits in the MIICR register |
MIICR_MAUTO = 0x80 |
MIICR_RCMD = 0x40 |
MIICR_WCMD = 0x20 |
MIICR_MDPM = 0x10 |
MIICR_MOUT = 0x08 |
MIICR_MDO = 0x04 |
MIICR_MDI = 0x02 |
MIICR_MDC = 0x01 |
; Bits in the EECSR register |
EECSR_EEPR = 0x80 ; eeprom programed status, 73h means programed |
EECSR_EMBP = 0x40 ; eeprom embeded programming |
EECSR_AUTOLD = 0x20 ; eeprom content reload |
EECSR_DPM = 0x10 ; eeprom direct programming |
EECSR_CS = 0x08 ; eeprom CS pin |
EECSR_SK = 0x04 ; eeprom SK pin |
EECSR_DI = 0x02 ; eeprom DI pin |
EECSR_DO = 0x01 ; eeprom DO pin |
; Bits in the BCR0 register |
BCR0_CRFT2 = 0x20 |
BCR0_CRFT1 = 0x10 |
BCR0_CRFT0 = 0x08 |
BCR0_DMAL2 = 0x04 |
BCR0_DMAL1 = 0x02 |
BCR0_DMAL0 = 0x01 |
; Bits in the BCR1 register |
BCR1_CTSF = 0x20 |
BCR1_CTFT1 = 0x10 |
BCR1_CTFT0 = 0x08 |
BCR1_POT2 = 0x04 |
BCR1_POT1 = 0x02 |
BCR1_POT0 = 0x01 |
; Bits in the CFGA register |
CFGA_EELOAD = 0x80 ; enable eeprom embeded and direct programming |
CFGA_JUMPER = 0x40 |
CFGA_MTGPIO = 0x08 |
CFGA_T10EN = 0x02 |
CFGA_AUTO = 0x01 |
; Bits in the CFGB register |
CFGB_PD = 0x80 |
CFGB_POLEN = 0x02 |
CFGB_LNKEN = 0x01 |
; Bits in the CFGC register |
CFGC_M10TIO = 0x80 |
CFGC_M10POL = 0x40 |
CFGC_PHY1 = 0x20 |
CFGC_PHY0 = 0x10 |
CFGC_BTSEL = 0x08 |
CFGC_BPS2 = 0x04 ; bootrom select[2] |
CFGC_BPS1 = 0x02 ; bootrom select[1] |
CFGC_BPS0 = 0x01 ; bootrom select[0] |
; Bits in the CFGD register |
CFGD_GPIOEN = 0x80 |
CFGD_DIAG = 0x40 |
CFGD_MAGIC = 0x10 |
CFGD_RANDOM = 0x08 |
CFGD_CFDX = 0x04 |
CFGD_CEREN = 0x02 |
CFGD_CETEN = 0x01 |
; Bits in RSR |
RSR_RERR = 0x00000001 |
RSR_CRC = 0x00000002 |
RSR_FAE = 0x00000004 |
RSR_FOV = 0x00000008 |
RSR_LONG = 0x00000010 |
RSR_RUNT = 0x00000020 |
RSR_SERR = 0x00000040 |
RSR_BUFF = 0x00000080 |
RSR_EDP = 0x00000100 |
RSR_STP = 0x00000200 |
RSR_CHN = 0x00000400 |
RSR_PHY = 0x00000800 |
RSR_BAR = 0x00001000 |
RSR_MAR = 0x00002000 |
RSR_RXOK = 0x00008000 |
RSR_ABNORMAL = RSR_RERR+RSR_LONG+RSR_RUNT |
; Bits in TSR |
TSR_NCR0 = 0x00000001 |
TSR_NCR1 = 0x00000002 |
TSR_NCR2 = 0x00000004 |
TSR_NCR3 = 0x00000008 |
TSR_COLS = 0x00000010 |
TSR_CDH = 0x00000080 |
TSR_ABT = 0x00000100 |
TSR_OWC = 0x00000200 |
TSR_CRS = 0x00000400 |
TSR_UDF = 0x00000800 |
TSR_TBUFF = 0x00001000 |
TSR_SERR = 0x00002000 |
TSR_JAB = 0x00004000 |
TSR_TERR = 0x00008000 |
TSR_ABNORMAL = TSR_TERR+TSR_OWC+TSR_ABT+TSR_JAB+TSR_CRS |
TSR_OWN_BIT = 0x80000000 |
CB_DELAY_LOOP_WAIT = 10 ; 10ms |
; enabled mask value of irq |
W_IMR_MASK_VALUE = 0x1BFF ; initial value of IMR |
; Ethernet address filter type |
PKT_TYPE_DIRECTED = 0x0001 ; obsolete, directed address is always accepted |
PKT_TYPE_MULTICAST = 0x0002 |
PKT_TYPE_ALL_MULTICAST = 0x0004 |
PKT_TYPE_BROADCAST = 0x0008 |
PKT_TYPE_PROMISCUOUS = 0x0020 |
PKT_TYPE_LONG = 0x2000 |
PKT_TYPE_RUNT = 0x4000 |
PKT_TYPE_ERROR = 0x8000 ; accept error packets, e.g. CRC error |
; Loopback mode |
NIC_LB_NONE = 0x00 |
NIC_LB_INTERNAL = 0x01 |
NIC_LB_PHY = 0x02 ; MII or Internal-10BaseT loopback |
PKT_BUF_SZ = 1536 ; Size of each temporary Rx buffer. |
PCI_REG_MODE3 = 0x53 |
MODE3_MIION = 0x04 ; in PCI_REG_MOD3 OF PCI space |
; VIA Rhine revisions |
VT86C100A = 0x00 |
VTunknown0 = 0x20 |
VT6102 = 0x40 |
VT8231 = 0x50 ; Integrated MAC |
VT8233 = 0x60 ; Integrated MAC |
VT8235 = 0x74 ; Integrated MAC |
VT8237 = 0x78 ; Integrated MAC |
VTunknown1 = 0x7C |
VT6105 = 0x80 |
VT6105_B0 = 0x83 |
VT6105L = 0x8A |
VT6107 = 0x8C |
VTunknown2 = 0x8E |
VT6105M = 0x90 |
; Rx status bits |
RX_SBITS_RERR = 1 shl 0 |
RX_SBITS_CRC_ERROR = 1 shl 1 |
RX_SBITS_FAE = 1 shl 2 |
RX_SBITS_FOV = 1 shl 3 |
RX_SBITS_TOOLONG = 1 shl 4 |
RX_SBITS_RUNT = 1 shl 5 |
RX_SBITS_SERR = 1 shl 6 |
RX_SBITS_BUFF = 1 shl 7 |
RX_SBITS_EDP = 1 shl 8 |
RX_SBITS_STP = 1 shl 9 |
RX_SBITS_CHN = 1 shl 10 |
RX_SBITS_PHY = 1 shl 11 |
RX_SBITS_BAR = 1 shl 12 |
RX_SBITS_MAR = 1 shl 13 |
RX_SBITS_RESERVED_1 = 1 shl 14 |
RX_SBITS_RXOK = 1 shl 15 |
RX_SBITS_FRAME_LENGTH = 0x7FF shl 16 |
RX_SBITS_RESERVED_2 = 0xF shl 27 |
RX_SBITS_OWN_BIT = 1 shl 31 |
; Rx control bits |
RX_CBITS_RX_BUF_SIZE = 0x7FF |
RX_CBITS_EXTEND_RX_BUF_SIZE = 0xF shl 11 |
RX_CBITS_RESERVED_1 = 0x1FFFF shl 15 |
; Tx status bits |
TX_SBITS_NCR0 = 1 shl 0 |
TX_SBITS_NCR1 = 1 shl 1 |
TX_SBITS_NCR2 = 1 shl 2 |
TX_SBITS_NCR3 = 1 shl 3 |
TX_SBITS_COLS = 1 shl 4 |
TX_SBITS_RESERVED_1 = 1 shl 5 |
TX_SBITS_CDH = 1 shl 7 |
TX_SBITS_ABT = 1 shl 8 |
TX_SBITS_OWC = 1 shl 9 |
TX_SBITS_CRS = 1 shl 10 |
TX_SBITS_UDF = 1 shl 11 |
TX_SBITS_TBUFF = 1 shl 12 |
TX_SBITS_SERR = 1 shl 13 |
TX_SBITS_JAB = 1 shl 14 |
TX_SBITS_TERR = 1 shl 15 |
TX_SBITS_RESERVED_2 = 0x7FFF shl 16 |
TX_SBITS_OWN_BIT = 1 shl 31 |
; Tx control bits |
TX_CBITS_TX_BUF_SIZE = 0x7FF |
TX_CBITS_EXTEND_TX_BUF_SIZE = 0xF shl 11 |
TX_CBITS_CHN = 1 shl 15 |
TX_CBITS_CRC = 1 shl 16 |
TX_CBITS_RESERVED_1 = 0xF shl 17 |
TX_CBITS_STP = 1 shl 21 |
TX_CBITS_EDP = 1 shl 22 |
TX_CBITS_IC = 1 shl 23 |
TX_CBITS_RESERVED_2 = 0xFF shl 24 |
; Offsets to the device registers. |
StationAddr = 0x00 |
RxConfig = 0x06 |
TxConfig = 0x07 |
ChipCmd = 0x08 |
IntrStatus = 0x0C |
IntrEnable = 0x0E |
MulticastFilter0 = 0x10 |
MulticastFilter1 = 0x14 |
RxRingPtr = 0x18 |
TxRingPtr = 0x1C |
GFIFOTest = 0x54 |
MIIPhyAddr = 0x6C |
MIIStatus = 0x6D |
PCIBusConfig = 0x6E |
MIICmd = 0x70 |
MIIRegAddr = 0x71 |
MIIData = 0x72 |
MACRegEEcsr = 0x74 |
ConfigA = 0x78 |
ConfigB = 0x79 |
ConfigC = 0x7A |
ConfigD = 0x7B |
RxMissed = 0x7C |
RxCRCErrs = 0x7E |
MiscCmd = 0x81 |
StickyHW = 0x83 |
IntrStatus2 = 0x84 |
WOLcrClr = 0xA4 |
WOLcgClr = 0xA7 |
PwrcsrClr = 0xAC |
; Bits in the interrupt status/mask registers. |
IntrRxDone = 0x0001 |
IntrRxErr = 0x0004 |
IntrRxEmpty = 0x0020 |
IntrTxDone = 0x0002 |
IntrTxError = 0x0008 |
IntrTxUnderrun = 0x0010 |
IntrPCIErr = 0x0040 |
IntrStatsMax = 0x0080 |
IntrRxEarly = 0x0100 |
IntrRxOverflow = 0x0400 |
IntrRxDropped = 0x0800 |
IntrRxNoBuf = 0x1000 |
IntrTxAborted = 0x2000 |
IntrLinkChange = 0x4000 |
IntrRxWakeUp = 0x8000 |
IntrNormalSummary = 0x0003 |
IntrAbnormalSummary = 0xC260 |
IntrTxDescRace = 0x080000 ; mapped from IntrStatus2 |
IntrTxErrSummary = 0x082218 |
DEFAULT_INTR = (IntrRxDone or IntrRxErr or IntrRxEmpty or IntrRxOverflow or IntrRxDropped or IntrRxNoBuf) |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.pci_dev dd ? |
.pci_bus dd ? |
.revision db ? |
.irq_line db ? |
.chip_id dw ? |
.cur_rx dw ? |
.cur_tx dw ? |
.last_tx dw ? |
rb 0x100-(($ - device) and 0xff) ; align 256 |
.tx_ring rb tx_head.sizeof*TX_RING_SIZE |
rb 0x100-(($ - device) and 0xff) ; align 256 |
.rx_ring rb rx_head.sizeof*RX_RING_SIZE |
.size = $ - device |
end virtual |
virtual at 0 |
rx_head: |
.status dd ? |
.control dd ? |
.buff_addr dd ? ; address |
.next_desc dd ? ; |
.buff_addr_virt dd ? |
rd 3 ; alignment |
.sizeof: |
end virtual |
virtual at 0 |
tx_head: |
.status dd ? |
.control dd ? |
.buff_addr dd ? ; address |
.next_desc dd ? ; |
.buff_addr_virt dd ? |
rd 3 ; alignment |
.sizeof: |
end virtual |
section '.flat' code readable align 16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
DEBUGF 2,"Loading %s driver\n", my_service |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
ret |
endp |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
proc service_proc stdcall, ioctl:dword |
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
;------------------------------------------------------ |
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
cmp [IOCTL.out_size], 4 |
jb .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jb .fail |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jae .fail |
allocate_and_clear ebx, device.size, .fail ; Allocate the buffer for device structure |
; Fill in the direct call addresses into the struct |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; save the pci bus and device numbers |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
DEBUGF 1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4 |
; Ok, the eth_device structure is ready, let's probe the device |
;;; cli |
call probe ; this function will output in eax |
test eax, eax |
jnz .err_sti ; If an error occured, exit |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
;;; sti |
cmp eax, -1 |
je .destroy |
ret |
; If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
DEBUGF 1,"Trying to find device number of already registered device\n" |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 1,"Kernel says: %u\n", eax |
ret |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
; todo: reset device into virgin state |
.err_sti: |
sti |
.err: |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
;------------------------------------------------------ |
endp |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
probe: |
mov eax, [device.io_addr] |
DEBUGF 1, "Probing card at 0x%x\n", eax |
; make the card a bus master |
PCI_make_bus_master |
; get device id |
stdcall PciRead16, [device.pci_bus], [device.pci_dev], PCI_DEVICE_ID |
mov [device.chip_id], ax |
; get revision id. |
PCI_find_rev |
movzx eax, [device.revision] |
DEBUGF 1, "Card revision = 0x%x\n", eax |
; D-Link provided reset code (with comment additions) |
cmp al, 0x40 |
jb .below_x40 |
mov ax, [device.chip_id] |
DEBUGF 1, "Enabling Sticky Bit Workaround for Chip_id: 0x%x\n", ax |
; clear sticky bit before reset & read ethernet address |
set_io 0 |
set_io bySTICKHW |
in al, dx |
and al, 0xFC |
out dx, al |
; (bits written are cleared?) |
; disable force PME-enable |
set_io byWOLcgClr |
mov al, 0x80 |
out dx, al |
; disable power-event config bit |
mov al, 0xFF |
out dx, al |
; clear power status (undocumented in vt6102 docs?) |
set_io byPwrcsrClr |
out dx, al |
.below_x40: |
; Reset the chip to erase previous misconfiguration. |
set_io 0 |
set_io byCR0 |
mov ax, CR_SFRST |
out dx, ax |
; if vt3043 delay after reset |
cmp [device.revision], 0x40 |
jae @f |
mov esi, 2000 ; 2000ms |
call Sleep |
@@: |
; polling till software reset complete |
mov ecx, W_MAX_TIMEOUT |
.poll_again: |
in ax, dx |
test ax, CR_SFRST |
jz @f |
loop .poll_again |
DEBUGF 1, "Soft reset timeout!\n" |
@@: |
; issue AUTOLoad in EECSR to reload eeprom |
set_io byEECSR |
mov al, 0x20 |
out dx, al |
; if vt3065 delay after reset |
cmp [device.revision], 0x40 |
jb .not_vt3065 |
; delay 8ms to let MAC stable |
mov esi, 8 ; 8ms |
call Sleep |
; for 3065D, EEPROM reloaded will cause bit 0 in MAC_REG_CFGA |
; turned on. it makes MAC receive magic packet |
; automatically. So, we turn it off. (D-Link) |
set_io byCFGA |
in al, dx |
and al, 0xFE |
out dx, al |
; turn on bit2 in PCI configuration register 0x53 , only for 3065 |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], PCI_REG_MODE3 |
or al, MODE3_MIION |
stdcall PciWrite8, [device.pci_bus], [device.pci_dev], PCI_REG_MODE3, eax |
.not_vt3065: |
; back off algorithm, disable the right-most 4-bit off CFGD |
set_io 0 |
set_io byCFGD |
in al, dx |
and al, not (CFGD_RANDOM or CFGD_CFDX or CFGD_CEREN or CFGD_CETEN) |
out dx, al |
; reload eeprom |
call reload_eeprom |
; read MAC |
call read_mac |
; restart MII auto-negotiation |
stdcall WriteMII, 0, 1 shl 9, 1 |
DEBUGF 1, "Analyzing Media type, this may take several seconds" |
mov ecx, 5 |
.read_again: |
DEBUGF 1, "." |
mov esi, 1 |
call Sleep |
stdcall ReadMII, 1 |
test eax, 0x0020 |
jnz .read_done |
loop .read_again |
DEBUGF 1, "timeout!\n" |
.read_done: |
DEBUGF 1, " OK\n" |
if DEBUG |
set_io 0 |
set_io 0x6C |
in al, dx |
and eax, 0xFF |
DEBUGF 1, "MII : Address %x\n", ax |
stdcall ReadMII, 1 |
DEBUGF 1, "status 0x%x\n", ax |
stdcall ReadMII, 4 |
DEBUGF 1, "advertising 0x%x\n", ax |
stdcall ReadMII, 5 |
DEBUGF 1, "link 0x%x\n", ax |
end if |
; query MII to know LineSpeed, duplex mode |
set_io 0 |
set_io MIIStatus |
in al, dx |
test al, MIISR_SPEED |
jz .100mbps |
DEBUGF 1, "Linespeed=10Mbs\n" |
jmp @f |
.100mbps: |
DEBUGF 1, "Linespeed=100Mbs\n" |
@@: |
call QueryAuto |
test eax, 1 |
jz .halfduplex |
DEBUGF 1, "Fullduplex\n" |
set_io 0 |
set_io byCR0 |
mov ax, CR_FDX |
out dx, ax |
jmp @f |
.halfduplex: |
DEBUGF 1, "Halfduplex\n" |
@@: |
; set MII 10 FULL ON, only apply in vt3043 |
cmp [device.chip_id], 0x3043 |
jne @f |
stdcall WriteMII, 0x17, 1 shl 1, 1 |
@@: |
; turn on MII link change |
set_io 0 |
set_io byMIICR |
in al, dx |
and al, 0x7F |
out dx, al |
push eax |
call MIIDelay |
set_io byMIIAD |
mov al, 0x41 |
out dx, al |
call MIIDelay |
pop eax |
or al, 0x80 |
set_io byMIICR |
out dx, al |
;**************************************************************************; |
;* ETH_RESET - Reset adapter *; |
;**************************************************************************; |
reset: |
DEBUGF 1, "reset\n" |
; attach int handler |
movzx eax, [device.irq_line] |
DEBUGF 2,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 2,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
; Soft reset the chip. |
set_io 0 |
set_io byCR0 |
mov ax, CR_SFRST |
out dx, ax |
call MIIDelay |
; Initialize rings |
call init_ring |
; Setup Multicast |
call set_rx_mode |
; set TCR RCR threshold to store and forward |
set_io 0 |
set_io byBCR0 |
mov al, 0x3E |
out dx, al |
set_io byBCR1 |
mov al, 0x38 |
out dx, al |
set_io byRCR |
mov al, 0x2C |
out dx, al |
set_io byTCR |
mov al, 0x60 |
out dx, al |
; Set Fulldupex |
call QueryAuto |
test eax, eax ; full duplex? |
jz @f |
set_io 0 |
set_io byCFGD |
mov al, CFGD_CFDX |
out dx, al |
set_io byCR0 |
mov ax, CR_FDX |
out dx, ax |
@@: |
; ENABLE interrupts |
set_io 0 |
set_io byIMR0 |
mov ax, DEFAULT_INTR |
out dx, ax |
; KICK NIC to WORK |
set_io byCR0 |
in ax, dx |
and ax, not CR_STOP |
or ax, CR_STRT or CR_TXON or CR_RXON or CR_DPOLL |
out dx, ax |
; Set the mtu, kernel will be able to send now |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
; say reset was successfull |
xor eax, eax |
ret |
align 4 |
unload: |
call reset |
push eax edx |
DEBUGF 1, "rhine disable\n" |
; Switch to loopback mode to avoid hardware races. |
set_io 0 |
set_io byTCR |
mov al, 0x61 |
out dx, al |
; Stop the chip's Tx and Rx processes. |
set_io byCR0 |
mov ax, CR_STOP |
out dx, ax |
pop edx eax |
ret |
align 4 |
reload_eeprom: |
DEBUGF 1, "Reload eeprom\n" |
set_io 0 |
set_io byEECSR |
mov al, 0x20 |
out dx, al |
; Typically 2 cycles to reload. |
mov ecx, 150 |
.reload: |
in al, dx |
test al, 0x20 |
jz @f |
loop .reload |
DEBUGF 1, "Reload timeout!\n" |
@@: |
ret |
; Initialize the Rx and Tx rings, along with various 'dev' bits. |
align 4 |
init_ring: |
DEBUGF 1, "Init ring\n" |
lea edi, [device.rx_ring] |
mov eax, edi |
GetRealAddr |
mov esi, eax |
push esi |
mov ecx, RX_RING_SIZE |
.rx_init: |
add esi, rx_head.sizeof |
mov [edi + rx_head.status], RX_SBITS_OWN_BIT |
mov [edi + rx_head.control], PKT_BUF_SZ |
push ecx |
stdcall KernelAlloc, PKT_BUF_SZ |
pop ecx |
mov [edi + rx_head.buff_addr_virt], eax |
GetRealAddr |
mov [edi + rx_head.buff_addr], eax ; buffer ptr |
mov [edi + rx_head.next_desc], esi ; next head |
add edi, rx_head.sizeof |
dec ecx |
jnz .rx_init |
pop [edi - rx_head.sizeof + rx_head.next_desc] ; Mark the last entry as wrapping the ring. |
lea edi, [device.tx_ring] |
mov eax, edi |
GetRealAddr |
mov esi, eax |
push esi |
mov ecx, TX_RING_SIZE |
.tx_init: |
add esi, tx_head.sizeof |
mov [edi + tx_head.status], 0 |
mov [edi + tx_head.control], 0x00E08000 |
mov [edi + tx_head.buff_addr], 0 |
mov [edi + tx_head.next_desc], esi |
mov [edi + tx_head.buff_addr_virt], 0 |
add edi, tx_head.sizeof |
dec ecx |
jnz .tx_init |
pop [edi - tx_head.sizeof + tx_head.next_desc] ; Mark the last entry as wrapping the ring. |
; write Descriptors to MAC |
lea eax, [device.rx_ring] |
GetRealAddr |
set_io 0 |
set_io dwCurrentRxDescAddr |
out dx, eax |
lea eax, [device.tx_ring] |
GetRealAddr |
set_io dwCurrentTxDescAddr |
out dx, eax |
xor eax, eax |
mov [device.cur_rx], ax |
mov [device.cur_tx], ax |
mov [device.last_tx], ax |
ret |
align 4 |
QueryAuto: |
DEBUGF 1, "Query Auto\n" |
push ecx |
stdcall ReadMII, 0x04 ; advertised |
mov ecx, eax |
stdcall ReadMII, 0x05 |
and ecx, eax |
xor eax, eax |
test ecx, 0x100 |
jnz .one |
and ecx, 0x1C0 |
cmp ecx, 0x40 |
jne .zero |
.one: |
inc eax |
DEBUGF 1, "AutoNego OK!\n" |
.zero: |
pop ecx |
ret |
proc ReadMII stdcall, byMIIIndex:dword |
; DEBUGF 1, "ReadMII Index=%x\n", [byMIIIndex] |
push esi ebx ecx edx |
set_io 0 |
set_io byMIIAD |
in al, dx |
mov bl, al |
set_io byMIICR |
in al, dx |
mov bh, al |
and al, 0x7F |
out dx, al |
call MIIDelay |
mov al, byte [byMIIIndex] |
set_io byMIIAD |
out dx, al |
call MIIDelay |
set_io byMIICR |
in al, dx |
or al, 0x40 |
out dx, al |
mov ecx, 200 |
.read_again: |
in al, dx |
test al, 0x40 |
jz @f |
mov esi, 10 |
call Sleep |
dec ecx |
jnz .read_again |
DEBUGF 1, "\nReadMII timeout!\n" |
@@: |
call MIIDelay |
set_io byMIIAD |
in ax, dx |
push eax |
mov ax, bx |
set_io byMIIAD |
out dx, al |
shr ax, 8 |
set_io byMIICR |
out dx, al |
call MIIDelay |
pop eax |
and eax, 0xFFFF |
rol ax, 8 ;;;;; I dont know how or why but it seems needed... |
pop edx ecx ebx esi |
ret |
endp |
proc WriteMII stdcall, byMIISetByte:dword, byMIISetBit:dword, byMIIOP:dword |
; DEBUGF 1, "WriteMII SetByte=%x SetBit=%x OP=%x\n", [byMIISetByte], [byMIISetBit], [byMIIOP] |
push ebx eax ecx edx |
set_io 0 |
set_io byMIIAD |
in al, dx |
mov bl, al |
set_io byMIICR |
in al, dx |
mov bh, al |
and al, 0x7F |
out dx, al |
call MIIDelay |
mov al, byte [byMIISetByte] |
set_io byMIIAD |
out dx, al |
call MIIDelay |
set_io byMIICR |
in al, dx |
or al, 0x40 |
out dx, al |
mov ecx, 200 |
.read_again0: |
in al, dx |
test al, 0x40 |
jz .done |
mov esi, 10 |
call Sleep |
dec ecx |
jnz .read_again0 |
DEBUGF 1, "WriteMII timeout 1\n" |
.done: |
call MIIDelay |
set_io wMIIDATA |
in ax, dx |
mov ecx, [byMIISetBit] |
rol cx, 8 ;;;;;;;;;;;;;;;;; CHECKME |
cmp byte [byMIIOP], 0 |
jne @f |
not ecx |
and ax, cx |
jmp .end_mascarad |
@@: |
or ax, cx |
.end_mascarad: |
set_io wMIIDATA |
out dx, ax |
call MIIDelay |
set_io byMIICR |
in al, dx |
or al, 0x20 |
out dx, al |
mov ecx, 200 |
.read_again1: |
in al, dx |
test al, 0x20 |
jz @f |
mov esi, 10 |
call Sleep |
dec ecx |
jnz .read_again1 |
DEBUGF 1, "WriteMII timeout 2\n" |
@@: |
call MIIDelay |
mov ax, bx |
and al, 0x7F |
set_io byMIIAD |
out dx, al |
shr ax, 8 |
set_io byMIICR |
out dx, al |
call MIIDelay |
pop edx ecx eax ebx |
ret |
endp |
align 4 |
MIIDelay: |
mov ecx, 0x7FFF |
@@: |
in al, 0x61 |
in al, 0x61 |
in al, 0x61 |
in al, 0x61 |
loop @b |
ret |
align 4 |
set_rx_mode: |
DEBUGF 1, "Set RX mode\n" |
; ! IFF_PROMISC |
mov eax, 0xffffffff |
set_io 0 |
set_io byMAR0 |
out dx, eax |
set_io byMAR4 |
out dx, eax |
set_io byRCR |
mov al, 0x6C ;rx_mode = 0x0C; |
out dx, al ;outb(0x60 /* thresh */ | rx_mode, byRCR ); |
ret |
; Beware of PCI posted writes |
macro IOSYNC |
{ |
set_io StationAddr |
in al, dx |
} |
align 4 |
read_mac: |
DEBUGF 1, "Ethernet Address: " |
lea edi, [device.mac] |
set_io 0 |
set_io byPAR0 |
mov ecx, 6 |
.next: |
in al, dx |
stosb |
DEBUGF 1, "-%x", al |
inc edx |
dec ecx |
jnz .next |
DEBUGF 1, "\n" |
ret |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
transmit: |
DEBUGF 2,"\nTransmitting packet, buffer:%x, size:%u\n", [esp+4], [esp+8] |
mov eax, [esp+4] |
DEBUGF 2,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp+8], 1514 |
ja .fail |
cmp dword [esp+8], 60 |
jb .fail |
movzx eax, [device.cur_tx] |
mov ecx, tx_head.sizeof |
mul ecx |
lea edi, [device.tx_ring] |
add edi, eax |
cmp [edi + tx_head.buff_addr_virt], 0 |
jne .fail |
mov eax, [esp+4] |
mov [edi + tx_head.buff_addr_virt], eax |
GetRealAddr |
mov [edi + tx_head.buff_addr], eax |
mov ecx, [esp+8] |
and ecx, TX_CBITS_TX_BUF_SIZE |
or ecx, 0x00E08000 |
mov [edi + tx_head.control], ecx |
or [edi + tx_head.status], TX_SBITS_OWN_BIT |
set_io 0 |
set_io byCR1 |
in al, dx |
or al, CR1_TDMD1 |
out dx, al |
inc [device.cur_tx] |
and [device.cur_tx], TX_RING_SIZE-1 |
;outw(IMRShadow,byIMR0); ; |
; Update stats |
inc [device.packets_tx] |
mov ecx, [esp+8] ;;;;; |
add dword [device.bytes_tx], ecx |
adc dword [device.bytes_tx + 4], 0 |
ret 8 |
.fail: |
DEBUGF 1, "Failed!\n" |
ret 8 |
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int ", my_service |
; Find pointer of device wich made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io IntrStatus |
in ax, dx |
out dx, ax ; send it back to ACK |
test ax, ax |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
DEBUGF 1, "not for me\n" |
ret |
.got_it: |
DEBUGF 1, "status=0x%x\n", ax |
push ax |
test ax, IntrRxDone |
jz .not_RX |
push ebx |
.more_RX: |
pop ebx |
; Get the current descripter pointer |
movzx eax, [device.cur_rx] |
mov ecx, rx_head.sizeof |
mul ecx |
lea edi, [device.rx_ring] |
add edi, eax |
; Check it's status |
test [edi + rx_head.status], RX_SBITS_OWN_BIT |
jnz .not_bit_own |
DEBUGF 1, "Packet status = 0x%x\n", [edi + rx_head.status] |
; TODO: check error bits |
; get length |
mov ecx, [edi + rx_head.status] |
and ecx, RX_SBITS_FRAME_LENGTH |
shr ecx, 16 |
sub ecx, 4 ; We dont want CRC |
; Update stats |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc [device.packets_rx] |
; Push packet size and pointer, kernel will need it.. |
push ebx |
push .more_RX ; return ptr |
push ecx ; full packet size |
push [edi + rx_head.buff_addr_virt] |
; reset the RX descriptor |
push edi |
stdcall KernelAlloc, PKT_BUF_SZ |
pop edi |
mov [edi + rx_head.buff_addr_virt], eax |
GetRealAddr |
mov [edi + rx_head.buff_addr], eax |
mov [edi + rx_head.status], RX_SBITS_OWN_BIT |
; Use next descriptor next time |
inc [device.cur_rx] |
and [device.cur_rx], RX_RING_SIZE - 1 |
; At last, send packet to kernel |
jmp Eth_input |
.not_bit_own: |
.not_RX: |
pop ax |
test ax, IntrTxDone |
jz .not_TX |
.loop_tx: |
movzx eax, [device.last_tx] |
mov ecx, tx_head.sizeof |
mul ecx |
lea edi, [device.tx_ring] |
add edi, eax |
test [edi + tx_head.status], TX_SBITS_OWN_BIT |
jnz .not_TX |
cmp [edi + tx_head.buff_addr_virt], 0 |
je .not_TX |
DEBUGF 1,"Freeing buffer 0x%x\n", [edi + tx_head.buff_addr_virt] |
push [edi + tx_head.buff_addr_virt] |
mov [edi + tx_head.buff_addr_virt], 0 |
call KernelFree |
inc [device.last_tx] |
and [device.last_tx], TX_RING_SIZE - 1 |
jmp .loop_tx |
.not_TX: |
; On Rhine-II, Bit 3 indicates Tx descriptor write-back race. |
if 0 |
cmp [device.chip_id], 0x3065 ;if (tp->chip_id == 0x3065) |
jne @f |
push ax |
xor eax, eax |
set_io IntrStatus2 |
in al, dx ; intr_status |= inb(nic->ioaddr + IntrStatus2) << 16; |
shl eax, 16 |
pop ax |
@@: |
end if |
if 0 |
; Acknowledge all of the current interrupt sources ASAP. |
xor ecx, ecx |
test eax, IntrTxDescRace |
jz @f |
set_io 0 |
set_io IntrStatus2 |
push ax |
mov al, 0x08 |
out dx, al |
pop ax |
@@: |
set_io 0 |
set_io IntrStatus |
out dx, ax |
IOSYNC |
end if |
ret |
; End of code |
section '.data' data readable writable align 16 ; place all uninitialized data here |
align 4 ; Place all initialised data here |
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'RHINE',0 ; max 16 chars including zero |
devicelist: |
dd 0x30431106, rhine_3043;, RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII or ReqTxAlign or HasV1TxStat |
dd 0x61001106, rhine_6100;, RHINE_IOTYPE, RHINE_I_IOSIZE, CanHaveMII or ReqTxAlign or HasV1TxStat |
dd 0x30651106, rhine_6102;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL |
dd 0x31061106, rhine_6105;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL |
; Duplicate entry, with 'M' features enabled. |
dd 0x31061106, rhine_6105;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL or HasIPChecksum or HasVLAN |
dd 0x30531106, rhine_3053;, RHINE_IOTYPE, RHINEII_IOSIZE, CanHaveMII or HasWOL |
dd 0 |
rhine_3043 db "VIA VT3043 Rhine", 0 |
rhine_6100 db "VIA VT86C100A Rhine", 0 |
rhine_6102 db "VIA VT6102 Rhine-II", 0 |
rhine_6105 db "VIA VT6105LOM Rhine-III (3106)", 0 |
rhine_3053 db "VIA VT6105M Rhine-III (3053 prototype)", 0 |
include_debug_strings ; All data wich FDO uses will be included here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
/kernel/branches/net/drivers/sis900.asm |
---|
0,0 → 1,1214 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; Ethernet driver for KolibriOS ;; |
;; This is an adaptation of MenuetOS driver with minimal changes. ;; |
;; Changes were made by CleverMouse. Original copyright follows. ;; |
;; ;; |
;; This driver is based on the SIS900 driver from ;; |
;; the etherboot 5.0.6 project. The copyright statement is ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;; remaining parts Copyright 2004 Jason Delozier, ;; |
;; cordata51@hotmail.com ;; |
;; ;; |
;; See file COPYING for details ;; |
;; ;; |
;; Updates: ;; |
;; Revision Look up table and SIS635 Mac Address by Jarek Pelczar ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
format MS COFF |
NUM_RX_DESC = 4 ; Number of RX descriptors |
NUM_TX_DESC = 4 ; Number of TX descriptors |
RX_BUFF_SZ = 1520 ; Buffer size for each Rx buffer |
TX_BUFF_SZ = 1516 ; Buffer size for each Tx buffer |
MAX_ETH_FRAME_SIZE = 1516 |
API_VERSION = 0x01000100 |
DRIVER_VERSION = 5 |
MAX_DEVICES = 16 |
DEBUG = 1 |
__DEBUG__ = 1 |
__DEBUG_LEVEL__ = 1 |
DSIZE = 0x00000fff |
CRC_SIZE = 4 |
RFADDR_shift = 16 |
; If you are having problems sending/receiving packet try changing the |
; Max DMA Burst, Possible settings are as follows: |
; |
; 0x00000000 = 512 bytes |
; 0x00100000 = 4 bytes |
; 0x00200000 = 8 bytes |
; 0x00300000 = 16 bytes |
; 0x00400000 = 32 bytes |
; 0x00500000 = 64 bytes |
; 0x00600000 = 128 bytes |
; 0x00700000 = 256 bytes |
RX_DMA = 0x00600000 |
TX_DMA = 0x00600000 |
;------------------------------------------------------------------------------------------------- |
; Symbolic offsets to registers. |
cr = 0x0 ; Command Register |
cfg = 0x4 ; Configuration Register |
mear = 0x8 ; EEPROM Access Register |
ptscr = 0xc ; PCI Test Control Register |
isr = 0x10 ; Interrupt Status Register |
imr = 0x14 ; Interrupt Mask Register |
ier = 0x18 ; Interrupt Enable Register |
epar = 0x18 ; Enhanced PHY Access Register |
txdp = 0x20 ; Transmit Descriptor Pointer Register |
txcfg = 0x24 ; Transmit Configuration Register |
rxdp = 0x30 ; Receive Descriptor Pointer Register |
rxcfg = 0x34 ; Receive Configuration Register |
flctrl = 0x38 ; Flow Control Register |
rxlen = 0x3c ; Receive Packet Length Register |
rfcr = 0x48 ; Receive Filter Control Register |
rfdr = 0x4C ; Receive Filter Data Register |
pmctrl = 0xB0 ; Power Management Control Register |
pmer = 0xB4 ; Power Management Wake-up Event Register |
; Command Register Bits |
RELOAD = 0x00000400 |
ACCESSMODE = 0x00000200 |
RESET = 0x00000100 |
SWI = 0x00000080 |
RxRESET = 0x00000020 |
TxRESET = 0x00000010 |
RxDIS = 0x00000008 |
RxENA = 0x00000004 |
TxDIS = 0x00000002 |
TxENA = 0x00000001 |
; Configuration Register Bits |
DESCRFMT = 0x00000100 ; 7016 specific |
REQALG = 0x00000080 |
SB = 0x00000040 |
POW = 0x00000020 |
EXD = 0x00000010 |
PESEL = 0x00000008 |
LPM = 0x00000004 |
BEM = 0x00000001 |
RND_CNT = 0x00000400 |
FAIR_BACKOFF = 0x00000200 |
EDB_MASTER_EN = 0x00002000 |
; Eeprom Access Reigster Bits |
MDC = 0x00000040 |
MDDIR = 0x00000020 |
MDIO = 0x00000010 ; 7016 specific |
EECS = 0x00000008 |
EECLK = 0x00000004 |
EEDO = 0x00000002 |
EEDI = 0x00000001 |
; TX Configuration Register Bits |
ATP = 0x10000000 ; Automatic Transmit Padding |
MLB = 0x20000000 ; Mac Loopback Enable |
HBI = 0x40000000 ; HeartBeat Ignore (Req for full-dup) |
CSI = 0x80000000 ; CarrierSenseIgnore (Req for full-du |
; RX Configuration Register Bits |
AJAB = 0x08000000 ; |
ATX = 0x10000000 ; Accept Transmit Packets |
ARP = 0x40000000 ; accept runt packets (<64bytes) |
AEP = 0x80000000 ; accept error packets |
; Interrupt Register Bits |
WKEVT = 0x10000000 |
TxPAUSEEND = 0x08000000 |
TxPAUSE = 0x04000000 |
TxRCMP = 0x02000000 ; Transmit Reset Complete |
RxRCMP = 0x01000000 ; Receive Reset Complete |
DPERR = 0x00800000 |
SSERR = 0x00400000 |
RMABT = 0x00200000 |
RTABT = 0x00100000 |
RxSOVR = 0x00010000 |
HIBERR = 0x00008000 |
SWINT = 0x00001000 |
MIBINT = 0x00000800 |
TxURN = 0x00000400 |
TxIDLE = 0x00000200 |
TxERR = 0x00000100 |
TxDESC = 0x00000080 |
TxOK = 0x00000040 |
RxORN = 0x00000020 |
RxIDLE = 0x00000010 |
RxEARLY = 0x00000008 |
RxERR = 0x00000004 |
RxDESC = 0x00000002 |
RxOK = 0x00000001 |
; Interrupt Enable Register Bits |
IE = RxOK + TxOK |
; Revision ID |
SIS900B_900_REV = 0x03 |
SIS630A_900_REV = 0x80 |
SIS630E_900_REV = 0x81 |
SIS630S_900_REV = 0x82 |
SIS630EA1_900_REV = 0x83 |
SIS630ET_900_REV = 0x84 |
SIS635A_900_REV = 0x90 |
SIS900_960_REV = 0x91 |
; Receive Filter Control Register Bits |
RFEN = 0x80000000 ; enable |
RFAAB = 0x40000000 ; accept all broadcasts |
RFAAM = 0x20000000 ; accept all multicasts |
RFAAP = 0x10000000 ; accept all packets |
; Reveive Filter Data Mask |
RFDAT = 0x0000FFFF |
; Eeprom Address |
EEPROMSignature = 0x00 |
EEPROMVendorID = 0x02 |
EEPROMDeviceID = 0x03 |
EEPROMMACAddr = 0x08 |
EEPROMChecksum = 0x0b |
; The EEPROM commands include the alway-set leading bit. |
EEread = 0x0180 |
EEwrite = 0x0140 |
EEerase = 0x01C0 |
EEwriteEnable = 0x0130 |
EEwriteDisable = 0x0100 |
EEeraseAll = 0x0120 |
EEwriteAll = 0x0110 |
EEaddrMask = 0x013F |
EEcmdShift = 16 |
; For SiS962 or SiS963, request the eeprom software access |
EEREQ = 0x00000400 |
EEDONE = 0x00000200 |
EEGNT = 0x00000100 |
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
public START |
public version |
virtual at ebx |
device: |
ETH_DEVICE |
.io_addr dd ? |
.pci_bus dd ? |
.pci_dev dd ? |
.irq_line db ? |
.cur_rx db ? |
.cur_tx db ? |
.last_tx db ? |
.pci_revision db ? |
.table_entries db ? |
rb 2 ; alignment |
.txd rd (4 * NUM_TX_DESC) |
.rxd rd (4 * NUM_RX_DESC) |
.size = $ - device |
end virtual |
macro ee_delay { |
push eax |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
in eax, dx |
pop eax |
} |
section '.flat' code readable align 16 |
; Driver entry point - register our service when the driver is loading. |
; TODO: add needed operations when unloading |
START: |
cmp dword [esp+4], 1 |
jne .exit |
stdcall RegService, my_service, service_proc |
ret 4 |
.exit: |
xor eax, eax |
ret 4 |
; Service procedure for the driver - handle all I/O requests for the driver. |
; Currently handled requests are: SRV_GETVERSION = 0 and SRV_HOOK = 1. |
service_proc: |
; 1. Get parameter from the stack: [esp+4] is the first parameter, |
; pointer to IOCTL structure. |
mov edx, [esp+4] ; edx -> IOCTL |
; 2. Get request code and select a handler for the code. |
mov eax, [IOCTL.io_code] |
test eax, eax ; check for SRV_GETVERSION |
jnz @f |
; 3. This is SRV_GETVERSION request, no input, 4 bytes output, API_VERSION. |
; 3a. Output size must be at least 4 bytes. |
cmp [IOCTL.out_size], 4 |
jb .fail |
; 3b. Write result to the output buffer. |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
; 3c. Return success. |
xor eax, eax |
ret 4 |
@@: |
dec eax ; check for SRV_HOOK |
jnz .fail |
; 4. This is SRV_HOOK request, input defines the device to hook, no output. |
; 4a. The driver works only with PCI devices, |
; so input must be at least 3 bytes long. |
cmp [IOCTL.inp_size], 3 |
jb .fail |
; 4b. First byte of input is bus type, 1 stands for PCI. |
mov eax, [IOCTL.input] |
cmp byte [eax], 1 |
jne .fail |
; 4c. Second and third bytes of the input define the device: bus and dev. |
; Word in bx holds both bytes. |
mov bx, [eax+1] |
; 4d. Check if the device was already hooked, |
; scan through the list of known devices. |
; check if the device is already listed |
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax, [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp al, byte[device.pci_bus] |
jne @f |
cmp ah, byte[device.pci_dev] |
je .find_devicenum ; Device is already loaded, let's find it's device number |
@@: |
add esi, 4 |
loop .nextdevice |
; 4e. This device doesn't have its own eth_device structure yet, let's create one |
.firstdevice: |
; 4f. Check that we have place for new device. |
cmp [devices], MAX_DEVICES |
jae .fail |
; 4g. Allocate memory for device descriptor and receive+transmit buffers. |
; 4h. Zero the structure. |
allocate_and_clear ebx, device.size, .fail |
; 4i. Save PCI coordinates |
mov eax, [IOCTL.input] |
movzx ecx, byte[eax+1] |
mov [device.pci_bus], ecx |
movzx ecx, byte[eax+2] |
mov [device.pci_dev], ecx |
; 4j. Fill in the direct call addresses into the struct. |
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.unload], unload |
mov [device.name], my_service |
; 4k. Now, it's time to find the base io addres of the PCI device |
; TODO: implement check if bus and dev exist on this machine |
; Now, it's time to find the base io addres of the PCI device |
PCI_find_io |
; We've found the io address, find IRQ now |
PCI_find_irq |
; 4m. Add new device to the list (required for int_handler). |
mov eax, [devices] |
mov [device_list+4*eax], ebx |
inc [devices] |
; 4m. Ok, the eth_device structure is ready, let's probe the device |
call probe |
test eax, eax |
jnz .destroy |
; 4n. If device was successfully initialized, register it for the kernel. |
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
cmp eax, -1 |
je .destroy |
ret 4 |
; 5. If the device was already loaded, find the device number and return it in eax |
.find_devicenum: |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
ret 4 |
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
.destroy: |
dec [devices] |
; todo: reset device into virgin state |
.err: |
stdcall KernelFree, ebx |
.fail: |
xor eax, eax |
ret 4 |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
; - Detach int handler |
; - Remove device from local list |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
or eax,-1 |
ret |
;*************************************************************************** |
; |
; probe |
; |
; checks the card and enables it |
; |
; TODO: probe mii transceivers |
; |
;*************************************************************************** |
align 4 |
probe: |
DEBUGF 1, "Probe\n" |
; wake up device CHECKME |
stdcall PciWrite8, [device.pci_bus], [device.pci_dev], 0x40, 0 |
PCI_make_bus_master |
PCI_adjust_latency 64 |
; Get Card Revision |
stdcall PciRead8, [device.pci_bus], [device.pci_dev], 0x08 |
mov [device.pci_revision], al ; save the revision for later use |
; Look up through the specific_table |
mov esi, specific_table |
.tableloop: |
cmp dword [esi], 0 ; Check if we reached end of the list |
je .notsupported |
cmp al, [esi] ; Check if revision is OK |
je .ok |
add esi, 12 ; Advance to next entry |
jmp .tableloop |
.ok: |
call dword[esi + 4] ; "get MAC" function |
; Set table entries |
mov [device.table_entries], 16 |
cmp [device.pci_revision], SIS635A_900_REV |
jae @f |
cmp [device.pci_revision], SIS900B_900_REV |
je @f |
mov [device.table_entries], 8 |
@@: |
; TODO: Probe for mii transceiver |
jmp reset |
.notsupported: |
DEBUGF 1, "Device not supported\n" |
or eax, -1 |
ret |
reset: |
DEBUGF 1, "reset\n" |
movzx eax, [device.irq_line] |
stdcall AttachIntHandler, eax, int_handler, 0 |
;-------------------------------------------- |
; Disable Interrupts and reset Receive Filter |
set_io 0 |
set_io ier |
xor eax, eax |
out dx, eax |
set_io imr |
out dx, eax |
set_io rfcr |
out dx, eax |
;----------- |
; Reset Card |
set_io cr |
in eax, dx ; Get current Command Register |
or eax, RESET + RxRESET + TxRESET ; set flags |
out dx, eax ; Write new Command Register |
;---------- |
; Wait loop |
set_io isr |
mov ecx, 1000 |
.loop: |
dec ecx |
jz .fail |
in eax, dx ; read interrupt status |
test eax, TxRCMP + RxRCMP |
jz .loop |
DEBUGF 1, "status=%x\n", eax |
;------------------------------------------------------ |
; Set Configuration Register depending on Card Revision |
set_io cfg |
mov eax, PESEL ; Configuration Register Bit |
cmp [device.pci_revision], SIS635A_900_REV |
je .match |
cmp [device.pci_revision], SIS900B_900_REV ; Check card revision |
jne .done |
.match: ; Revision match |
or eax, RND_CNT ; Configuration Register Bit |
.done: |
out dx, eax |
DEBUGF 1, "Initialising RX Filter\n" |
; Get Receive Filter Control Register |
set_io rfcr |
in eax, dx |
push eax |
; disable packet filtering before setting filter |
and eax, not RFEN |
out dx, eax |
; load MAC addr to filter data register |
xor ecx, ecx |
.macloop: |
mov eax, ecx |
set_io 0 |
set_io rfcr |
shl eax, 16 ; high word of eax tells card which mac byte to write |
out dx, eax ; |
set_io rfdr |
mov ax, word [device.mac + ecx*2] ; Get Mac ID word |
out dx, ax ; Send Mac ID |
inc cl ; send next word |
cmp cl, 3 ; more to send? |
jne .macloop |
; enable packet filtering |
pop eax ; old register value |
set_io rfcr |
or eax, RFEN ; enable filtering |
out dx, eax ; set register |
DEBUGF 1, "Initialising TX Descriptors\n" |
mov ecx, NUM_TX_DESC |
lea esi, [device.txd] |
.txdescloop: |
lea eax, [esi + 16] ; next ptr |
GetRealAddr |
mov dword [esi], eax ; link to next desc |
mov dword [esi + 4], 0 ; status field |
mov dword [esi + 8], 0 ; ptr to buffer |
add esi, 16 |
dec ecx |
jnz .txdescloop |
lea eax, [device.txd] |
GetRealAddr |
mov dword [esi - 16], eax ; correct last descriptor link ptr |
set_io txdp ; TX Descriptor Pointer |
; lea eax, [device.txd] |
; GetRealAddr |
out dx, eax |
mov [device.cur_tx], 0 ; Set current tx descriptor to 0 |
mov [device.last_tx], 0 |
DEBUGF 1, "Initialising RX Descriptors\n" |
mov ecx, NUM_RX_DESC |
lea esi, [device.rxd] |
.rxdescloop: |
lea eax, [esi + 16] ; next ptr |
GetRealAddr |
mov dword [esi], eax |
mov dword [esi + 4], RX_BUFF_SZ ; size |
push ecx esi |
stdcall KernelAlloc, RX_BUFF_SZ |
pop esi ecx |
test eax, eax |
jz .fail |
mov dword [esi + 12], eax ; address |
GetRealAddr |
mov dword [esi + 8], eax ; real address |
add esi, 16 |
dec ecx |
jnz .rxdescloop |
lea eax, [device.rxd] |
GetRealAddr |
mov dword [esi - 16], eax ; correct last descriptor link ptr |
set_io 0 |
set_io rxdp |
; lea eax, [device.rxd] |
; GetRealAddr |
out dx, eax |
mov [device.cur_rx], 0 ; Set current rx descriptor to 0 |
DEBUGF 1, "setting RX mode\n" |
xor cl, cl |
.rxfilterloop: |
set_io 0 |
set_io rfcr ; Receive Filter Control Reg offset |
mov eax, 4 ; determine table entry |
add al, cl |
shl eax, 16 |
out dx, eax ; tell card which entry to modify |
set_io rfdr ; Receive Filter Control Reg offset |
mov eax, 0xffff ; entry value |
out dx, ax ; write value to table in card |
inc cl ; next entry |
cmp cl, [device.table_entries] |
jb .rxfilterloop |
set_io rfcr ; Receive Filter Control Register offset |
mov eax, RFAAB + RFAAM + RFAAP + RFEN |
out dx, eax |
set_io rxcfg ; Receive Config Register offset |
mov eax, ATX + RX_DMA + 2 ; 0x2 : RX Drain Threshold = 8*8=64 bytes |
out dx, eax |
DEBUGF 1, "setting TX mode\n" |
set_io txcfg ; Transmit config Register offset |
mov eax, ATP + HBI + CSI + TX_DMA + 0x120 |
; TX Fill threshold = 0x100 |
; TX Drain Threshold = 0x20 |
out dx, eax |
DEBUGF 1, "Enabling interrupts\n" |
set_io imr |
mov eax, IE ; Interrupt enable mask |
out dx, eax |
set_io cr |
in eax, dx |
or eax, RxENA ; Enable Receive |
out dx, eax |
set_io ier ; Interrupt enable |
mov eax, 1 |
out dx, eax |
mov [device.mtu], 1514 |
; Set link state to unknown |
mov [device.state], ETH_LINK_UNKOWN |
xor eax, eax |
ret |
.fail: |
DEBUGF 1, "Resetting device failed\n" |
or eax, -1 |
ret |
;*************************************************************************** |
; |
; SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model |
; |
; SiS962 or SiS963 model, use EEPROM to store MAC address. |
; EEPROM is shared by LAN and 1394. |
; When access EEPROM, send EEREQ signal to hardware first, and wait for EEGNT. |
; If EEGNT is ON, EEPROM is permitted to be accessed by LAN, otherwise is not. |
; After MAC address is read from EEPROM, send |
; EEDONE signal to refuse EEPROM access by LAN. |
; The EEPROM map of SiS962 or SiS963 is different to SiS900. |
; The signature field in SiS962 or SiS963 spec is meaningless. |
; |
; Return 0 is EAX = failure |
; |
;*************************************************************************** |
align 4 |
SIS960_get_mac_addr: |
DEBUGF 1, "SIS960 - get mac: " |
;------------------------------- |
; Send Request for eeprom access |
set_io 0 |
set_io mear ; Eeprom access register |
mov eax, EEREQ ; Request access to eeprom |
out dx, eax ; Send request |
;----------------------------------------------------- |
; Loop 4000 times and if access not granted, error out |
mov ecx, 4000 |
.loop: |
in eax, dx ; get eeprom status |
test eax, EEGNT ; see if eeprom access granted flag is set |
jnz .got_access ; if it is, go access the eeprom |
loop .loop ; else keep waiting |
DEBUGF 1, "Access to EEprom failed!\n", 0 |
set_io mear ; Eeprom access register |
mov eax, EEDONE ; tell eeprom we are done |
out dx, eax |
or eax, -1 ; error |
ret |
.got_access: |
;------------------------------------------ |
; EEprom access granted, read MAC from card |
; zero based so 3-16 bit reads will take place |
mov ecx, 2 |
.read_loop: |
mov eax, EEPROMMACAddr ; Base Mac Address |
add eax, ecx ; Current Mac Byte Offset |
push ecx |
call read_eeprom ; try to read 16 bits |
pop ecx |
mov word [device.mac+ecx*2], ax ; save 16 bits to the MAC ID varible |
dec ecx ; one less word to read |
jns .read_loop ; if more read more |
mov eax, 1 ; return non-zero indicating success |
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
;------------------------------------- |
; Tell EEPROM We are Done Accessing It |
.done: |
set_io 0 |
set_io mear ; Eeprom access register |
mov eax, EEDONE ; tell eeprom we are done |
out dx, eax |
xor eax, eax ; ok |
ret |
;*************************************************************************** |
; |
; get_mac_addr: - Get MAC address for stand alone SiS900 model |
; |
; Older SiS900 and friends, use EEPROM to store MAC address. |
; |
;*************************************************************************** |
align 4 |
SIS900_get_mac_addr: |
DEBUGF 1, "SIS900 - get mac: " |
;------------------------------------ |
; check to see if we have sane EEPROM |
mov eax, EEPROMSignature ; Base Eeprom Signature |
call read_eeprom ; try to read 16 bits |
cmp ax, 0xffff |
je .err |
test ax, ax |
je .err |
;----------- |
; Read MacID |
; zero based so 3-16 bit reads will take place |
mov ecx, 2 |
.loop: |
mov eax, EEPROMMACAddr ; Base Mac Address |
add eax, ecx ; Current Mac Byte Offset |
push ecx |
call read_eeprom ; try to read 16 bits |
pop ecx |
mov word [device.mac+ecx*2], ax ; save 16 bits to the MAC ID storage |
dec ecx ; one less word to read |
jns .loop ; if more read more |
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
xor eax, eax |
ret |
.err: |
DEBUGF 1, "Access to EEprom failed!\n", 0 |
or eax, -1 |
ret |
;*************************************************************************** |
; |
; Get_Mac_SIS635_900_REV: - Get MAC address for model 635 |
; |
;*************************************************************************** |
align 4 |
Get_Mac_SIS635_900_REV: |
DEBUGF 1, "SIS635 - get mac: " |
set_io 0 |
set_io rfcr |
in eax, dx |
mov esi, eax |
set_io cr |
or eax, RELOAD |
out dx, eax |
xor eax, eax |
out dx, eax |
;----------------------------------------------- |
; Disable packet filtering before setting filter |
set_io rfcr |
mov eax, esi |
and eax, not RFEN |
out dx, eax |
;--------------------------------- |
; Load MAC to filter data register |
xor ecx, ecx |
lea edi, [device.mac] |
.loop: |
set_io 0 |
set_io rfcr |
mov eax, ecx |
shl eax, RFADDR_shift |
out dx, eax |
set_io rfdr |
in ax, dx |
stosw |
inc ecx |
cmp ecx, 3 |
jb .loop |
;------------------------ |
; Enable packet filtering |
set_io rfcr |
mov eax, esi |
or eax, RFEN |
out dx, eax |
DEBUGF 2,"%x-%x-%x-%x-%x-%x\n",[device.mac]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
xor eax, eax |
ret |
;*************************************************************************** |
; |
; read_eeprom |
; |
; reads and returns a given location from EEPROM |
; |
; IN: si = addr |
; OUT: ax = data |
; |
;*************************************************************************** |
align 4 |
read_eeprom: |
set_io 0 |
set_io mear |
xor eax, eax ; start send |
out dx, eax |
ee_delay |
or eax, EECLK |
out dx, eax |
ee_delay |
;------------------------------------ |
; Send the read command |
or esi, EEread |
mov ecx, 1 shl 9 |
.loop: |
mov eax, EECS |
test esi, ecx |
jz @f |
or eax, EEDI |
@@: |
out dx, eax |
ee_delay |
or eax, EECLK |
out dx, eax |
ee_delay |
shr esi, 1 |
jnc .loop |
mov eax, EECS |
out dx, eax |
ee_delay |
;------------------------ |
; Read 16-bits of data in |
xor esi, esi |
mov cx, 16 |
.loop2: |
mov eax, EECS |
out dx, eax |
ee_delay |
or eax, EECLK |
out dx, eax |
ee_delay |
in eax, dx |
shl esi, 1 |
test eax, EEDO |
jz @f |
inc esi |
@@: |
loop .loop2 |
;---------------------------- |
; Terminate the EEPROM access |
xor eax, eax |
out dx, eax |
ee_delay |
mov eax, EECLK |
out dx, eax |
ee_delay |
movzx eax, si |
ret |
align 4 |
write_mac: |
DEBUGF 1,'Setting MAC is not supported for SIS900 card.\n' |
add esp, 6 |
ret |
;*************************************************************************** |
; Function |
; transmit |
; Description |
; Transmits a packet of data via the ethernet card |
; buffer pointer in [esp+4] |
; size of buffer in [esp+8] |
; pointer to device structure in ebx |
; |
;*************************************************************************** |
align 4 |
transmit: |
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
cmp dword [esp + 8], MAX_ETH_FRAME_SIZE |
ja .error |
cmp dword [esp + 8], 60 |
jb .error |
movzx ecx, [device.cur_tx] |
shl ecx, 4 ; *16 |
lea ecx, [device.txd + ecx] |
test dword [ecx + 4], 0x80000000 ; card owns descriptor ? |
jnz .error |
mov eax, [esp + 4] |
mov dword [ecx + 12], eax |
GetRealAddr |
mov dword [ecx + 8], eax ; buffer address |
mov eax, [esp + 8] |
and eax, DSIZE |
or eax, 0x80000000 ; card owns descriptor |
mov dword [ecx + 4], eax ; status field |
set_io 0 |
set_io cr |
in eax, dx |
or eax, TxENA ; Enable the transmit state machine |
out dx, eax |
inc [device.cur_tx] |
and [device.cur_tx], NUM_TX_DESC-1 |
; update stats |
mov ecx, [esp + 8] |
inc [device.packets_tx] |
add dword [device.bytes_tx], ecx |
adc dword [device.bytes_tx + 4], 0 |
.finish: |
DEBUGF 1,"Packet sent!\n" |
xor eax, eax |
ret 8 |
.error: |
DEBUGF 1,"ERROR!\n" |
stdcall KernelFree, [esp+4] |
or eax, -1 |
ret 8 |
;*************************************************************************** |
; |
; int_handler |
; |
; handles received IRQs, which signal received packets |
; |
; Currently only supports one descriptor per packet, if packet is fragmented |
; between multiple descriptors you will lose part of the packet |
; |
;*************************************************************************** |
align 4 |
int_handler: |
DEBUGF 1,"\n%s int\n", my_service |
; find pointer of device which made IRQ occur |
mov ecx, [devices] |
test ecx, ecx |
jz .nothing |
mov esi, device_list |
.nextdevice: |
mov ebx, [esi] |
set_io 0 |
set_io isr |
in eax, dx ; note that this clears all interrupts |
test ax, IE |
jnz .got_it |
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
.nothing: |
ret |
.got_it: |
DEBUGF 1,"Device: %x Status: %x ", ebx, ax |
test ax, RxOK |
jz .no_rx_ |
push ax |
.rx_loop: |
;----------- |
; Get Status |
movzx eax, [device.cur_rx] ; find current descriptor |
shl eax, 4 ; * 16 |
mov ecx, dword[device.rxd + eax + 4] ; get receive status |
;------------------------------------------- |
; Check RX_Status to see if packet is waiting |
test ecx, 0x80000000 |
jz .no_rx |
;---------------------------------------------- |
; There is a packet waiting check it for errors |
test ecx, 0x67C0000 ; see if there are any errors |
jnz .error_status |
;--------------------- |
; Check size of packet |
and ecx, DSIZE ; get packet size minus CRC |
sub ecx, CRC_SIZE ; make sure packet contains data |
jbe .error_size |
; update statistics |
inc dword [device.packets_rx] |
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
push ebx |
push .return |
push ecx ; packet size |
pushd [device.rxd + eax + 12] ; packet ptr |
DEBUGF 1, "Packet received OK\n" |
jmp Eth_input |
.return: |
pop ebx |
; Reset status, allow ethernet card access to descriptor |
stdcall KernelAlloc, RX_BUFF_SZ |
test eax, eax |
jz .fail |
movzx ecx, [device.cur_rx] |
shl ecx, 4 ; *16 |
lea ecx, [device.rxd + ecx] |
mov dword [ecx + 12], eax |
GetRealAddr |
mov dword [ecx + 8], eax |
mov dword [ecx + 4], RX_BUFF_SZ |
inc [device.cur_rx] ; get next descriptor |
and [device.cur_rx], NUM_RX_DESC-1 ; only 4 descriptors 0-3 |
jmp .rx_loop |
.no_rx: |
set_io 0 |
set_io cr |
in eax, dx |
or eax, RxENA ; Re-Enable the Receive state machine |
out dx, eax |
pop ax |
.no_rx_: |
test ax, TxOK |
jz .no_tx |
DEBUGF 1, "TX ok!\n" |
.tx_loop: |
movzx ecx, [device.last_tx] |
shl ecx, 4 ; *16 |
lea ecx, [device.txd + ecx] |
test dword [ecx + 4], 0x80000000 ; card owns descr |
jnz .no_tx |
cmp dword [ecx + 12], 0 |
je .no_tx |
DEBUGF 1, "Freeing packet = %x\n", [ecx + 12]:8 |
push dword [ecx + 12] |
mov dword [ecx + 12], 0 |
call KernelFree |
inc [device.last_tx] |
and [device.last_tx], NUM_TX_DESC-1 |
jmp .tx_loop |
.no_tx: |
ret |
.error_status: |
DEBUGF 1, "Packet error: %x\n", ecx |
jmp .fail |
.error_size: |
DEBUGF 1, "Packet too large/small\n" |
jmp .fail |
.fail: |
DEBUGF 1, "FAILED\n" |
jmp $ |
ret |
; End of code |
align 4 ; Place all initialised data here |
devices dd 0 |
specific_table: |
; dd SIS630A_900_REV, Get_Mac_SIS630A_900_REV, 0 |
; dd SIS630E_900_REV, Get_Mac_SIS630E_900_REV, 0 |
dd SIS630S_900_REV, Get_Mac_SIS635_900_REV, 0 |
dd SIS630EA1_900_REV, Get_Mac_SIS635_900_REV, 0 |
dd SIS630ET_900_REV, Get_Mac_SIS635_900_REV, 0 ;SIS630ET_900_REV_SpecialFN |
dd SIS635A_900_REV, Get_Mac_SIS635_900_REV, 0 |
dd SIS900_960_REV, SIS960_get_mac_addr, 0 |
dd SIS900B_900_REV, SIS900_get_mac_addr, 0 |
dd 0 ; end of list |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'SIS900',0 ; max 16 chars include zero |
include_debug_strings ; All data wich FDO uses will be included here |
section '.data' data readable writable align 16; place all uninitialized data place here |
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/drivers/sceletone.asm |
---|
0,0 → 1,173 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;driver sceletone |
format MS COFF |
DEBUG equ 1 |
API_VERSION equ 0 ;debug |
include 'proc32.inc' |
include 'imports.inc' |
struc IOCTL |
{ .handle dd ? |
.io_code dd ? |
.input dd ? |
.inp_size dd ? |
.output dd ? |
.out_size dd ? |
} |
virtual at 0 |
IOCTL IOCTL |
end virtual |
public START |
public service_proc |
public version |
DRV_ENTRY equ 1 |
DRV_EXIT equ -1 |
STRIDE equ 4 ;size of row in devices table |
SRV_GETVERSION equ 0 |
section '.flat' code readable align 16 |
proc START stdcall, state:dword |
cmp [state], 1 |
jne .exit |
.entry: |
if DEBUG |
mov esi, msgInit |
call SysMsgBoardStr |
end if |
stdcall RegService, my_service, service_proc |
ret |
.fail: |
.exit: |
xor eax, eax |
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 service_proc stdcall, ioctl:dword |
mov ebx, [ioctl] |
mov eax, [ebx+io_code] |
cmp eax, SRV_GETVERSION |
jne @F |
mov eax, [ebx+output] |
cmp [ebx+out_size], 4 |
jne .fail |
mov [eax], dword API_VERSION |
xor eax, eax |
ret |
@@: |
.fail: |
or eax, -1 |
ret |
endp |
restore handle |
restore io_code |
restore input |
restore inp_size |
restore output |
restore out_size |
align 4 |
proc detect |
locals |
last_bus dd ? |
endl |
xor eax, eax |
mov [bus], eax |
inc eax |
call PciApi |
cmp eax, -1 |
je .err |
mov [last_bus], eax |
.next_bus: |
and [devfn], 0 |
.next_dev: |
stdcall PciRead32, [bus], [devfn], dword 0 |
test eax, eax |
jz .next |
cmp eax, -1 |
je .next |
mov edi, devices |
@@: |
mov ebx, [edi] |
test ebx, ebx |
jz .next |
cmp eax, ebx |
je .found |
add edi, STRIDE |
jmp @B |
.next: |
inc [devfn] |
cmp [devfn], 256 |
jb .next_dev |
mov eax, [bus] |
inc eax |
mov [bus], eax |
cmp eax, [last_bus] |
jna .next_bus |
xor eax, eax |
ret |
.found: |
xor eax, eax |
inc eax |
ret |
.err: |
xor eax, eax |
ret |
endp |
DEVICE_ID equ 1234; pci device id |
VENDOR_ID equ 5678; device vendor id |
;all initialized data place here |
align 4 |
devices dd (DEVICE_ID shl 16)+VENDOR_ID |
dd 0 ;terminator |
version dd (5 shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'MY_SERVICE',0 ;max 16 chars include zero |
msgInit db 'detect hardware...',13,10,0 |
msgPCI db 'PCI accsess not supported',13,10,0 |
msgFail db 'device not found',13,10,0 |
section '.data' data readable writable align 16 |
;all uninitialized data place here |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/fdo.inc |
---|
0,0 → 1,432 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; |
; 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 |
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: |
add esp,4*8+4 |
mov edx,..str |
sub esp,4*8+4 |
else |
mov edx,_str |
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 |
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 |
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 |
mov eax,dword _hex |
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 ebx,al |
mov eax,1 |
; mov ecx,sys_msg_board |
; call ecx ; sys_msg_board |
stdcall SysMsgBoardChar |
popad |
ret |
debug_endf |
debug_func fdo_debug_outstr |
debug_beginf |
mov eax,1 |
.l1: dec esi |
js .l2 |
movzx ebx,byte[edx] |
or bl,bl |
jz .l2 |
; mov ecx,sys_msg_board |
; call ecx ; sys_msg_board |
stdcall SysMsgBoardChar |
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 |
@@: push 10 |
pop ecx |
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 __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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers/proc32.inc |
---|
0,0 → 1,268 |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ 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 } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ 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 } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ if parmbytes | localbytes |
push ebp |
mov ebp,esp |
if localbytes |
sub esp,localbytes |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
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 } |
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 \} |
virtual at ebp+8 |
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 =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $ - (ebp+8) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
macro locals |
\{ virtual at ebp-localbytes+current |
macro label . \\{ deflocal@proc .,:, \\} |
struc db [val] \\{ \common deflocal@proc .,db,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,dw,dp,dd,dt,dq |
restruc rb,rw,rp,rd,rt,rq |
restruc byte,word,dword,pword,tword,qword |
current = $-(ebp-localbytes) |
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-1) shr 2)+1) shl 2 |
end if \} } |
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 } |
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 =dup (=?), val \{ ..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 \} } |
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 } |
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:keywords |
+Revision |
\ No newline at end of property |
/kernel/branches/net/drivers |
---|
Property changes: |
Added: svn:ignore |
+*.obj |
/kernel/branches/net/blkdev/disk.inc |
---|
0,0 → 1,1305 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2381 $ |
; ============================================================================= |
; ================================= 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 |
; 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(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 |
mutex MUTEX |
; Lock to protect the cache. |
; The following fields are inherited from data32.inc:cache_ideX. |
pointer dd ? |
data_size dd ? ; unused |
data dd ? |
sad_size dd ? |
search_start 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. |
align 4 |
; 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 |
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 a number of supported subfunctions, other dwords |
; point to handlers of corresponding subfunctions. |
; This field is 0 if file system is not recognized. |
; ...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 |
; ============================================================================= |
; ================================ 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 512-byte 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. |
; 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. |
push sizeof.DISK |
pop eax |
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. Note that it can change ebx. |
push ebx |
call malloc |
pop ebx |
; 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 |
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 |
call free |
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: |
push DISK_STATUS_INVALID_CALL |
pop eax |
ret 8 |
; The default implementation of DISKFUNC.read and DISKFUNC.write. |
disk_default_read: |
disk_default_write: |
push DISK_STATUS_INVALID_CALL |
pop eax |
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. Currently we can work only with 512-bytes sectors. Check this restriction. |
; The only exception is 2048-bytes CD/DVD, but they are not supported yet by |
; this code. |
cmp [esi+DISK.MediaInfo.SectorSize], 512 |
jz .doscan |
DEBUGF 1,'K : sector size is %d, only 512 is supported\n',[esi+DISK.MediaInfo.SectorSize] |
ret |
.doscan: |
; 3. Acquire the buffer for MBR and bootsector tests. See the comment before |
; the 'partition_buffer_users' variable. |
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 |
stdcall kernel_alloc, 512*3 |
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. |
; 4. 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 |
.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 9 and possibly step 10. |
test ebp, ebp |
jnz .mbr |
; 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. |
; 9. Test for MBR vs bootsector. |
; 9a. Check entries. If any is invalid, go to 10 (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 |
; 9b. Check types of the entries. If at least one is nonzero, go to 11 (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 |
; 9c. Empty partition table or bootsector with many zeroes? (rule B) |
cmp byte [ebx], 0EBh |
jz .notmbr |
cmp byte [ebx], 0E9h |
jnz .mbr |
.notmbr: |
; 10. 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] |
jmp .done |
.mbr: |
; 11. 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 |
; 12. Test whether we found a new EBR and should continue the loop. |
; 12a. If there was no next EBR, return. |
test ebp, ebp |
jz .done |
; Ok, we have EBR. |
; 12b. 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 |
; 12c. If extended partition has not yet started, start it. |
test eax, eax |
jnz @f |
mov eax, ebp |
@@: |
; 12c. If the limit is not exceeded, continue the loop. |
dec dword [esp] |
push eax ; store extended partition |
jnz .new_mbr |
.mbr_failed: |
.done: |
; 13. Cleanup after the loop. |
pop eax ; not important anymore |
pop eax ; not important anymore |
pop ebp ; restore ebp |
; 14. Release the buffer. |
; 14a. Test whether it is the global buffer or we have allocated it. |
cmp ebx, mbr_buffer |
jz .release_partition_buffer |
; 14b. If we have allocated it, free it. |
xchg eax, ebx |
call free |
jmp .nothing |
; 14c. Otherwise, release reference. |
.release_partition_buffer: |
lock dec [partition_buffer_users] |
.nothing: |
; 15. Return. |
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 |
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. |
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword |
; 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 ? |
end virtual |
; When disk_add_partition is called, ebx contains a pointer to |
; a two-sectors-sized buffer. This function saves ebx in the stack |
; immediately before ebp. |
virtual at ebp-4 |
.buffer dd ? |
end virtual |
; 1. Read the bootsector to the buffer. |
mov al, DISKFUNC.read |
mov ebx, [.buffer] |
add ebx, 512 |
push 1 |
stdcall disk_call_driver, ebx, dword [.start], dword [.start+4], esp |
; 2. Run tests for all supported filesystems. If at least one test succeeded, |
; go to 4. |
; For tests: qword [ebp+8] = partition start, qword [ebp+10h] = partition |
; length, [esp] = 0 if reading bootsector failed or 1 if succeeded, |
; ebx points to the buffer for bootsector. |
call fat_create_partition |
test eax, eax |
jnz .success |
; 3. No file system has recognized the volume, so just allocate the PARTITION |
; structure without extra fields. |
push sizeof.PARTITION |
pop eax |
call malloc |
test eax, eax |
jz .nothing |
mov edx, dword [.start] |
mov dword [eax+PARTITION.FirstSector], edx |
mov edx, dword [.start+4] |
mov dword [eax+PARTITION.FirstSector+4], edx |
mov edx, dword [.length] |
mov dword [eax+PARTITION.Length], edx |
mov edx, dword [.length+4] |
mov dword [eax+PARTITION.Length+4], edx |
mov [eax+PARTITION.Disk], esi |
and [eax+PARTITION.FSUserFunctions], 0 |
.success: |
.nothing: |
; 4. Return with eax = pointer to PARTITION or NULL. |
pop ecx |
ret |
; 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 -> name |
; ebp = 0 or rest of name relative to esi |
; 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. |
; 11a. Only "list directory" operation is applicable to /<diskname> path. Check |
; the operation code. If wrong, go to 13. |
cmp dword [ebx], 1 |
jnz .access_denied |
; 11b. If the media is inserted, use 'fs_dyndisk_next' as an enumeration |
; procedure. Otherwise, use 'fs_dyndisk_next_nomedia'. |
mov esi, fs_dyndisk_next_nomedia |
test edx, edx |
jz @f |
mov esi, fs_dyndisk_next |
@@: |
; 11c. Let the procedure from fs_lfn.inc do the job. |
jmp file_system_lfn.maindir_noesi |
.haspartition: |
; 12. The fs operation has specified some partition. |
; 12a. Store parameters for callback functions. |
push edx |
push ecx |
; 12b. Store callback functions. |
push dyndisk_cleanup |
push fs_dyndisk |
mov edi, esp |
; 12c. Let the procedure from fs_lfn.inc do the job. |
jmp file_system_lfn.found2 |
.access_denied: |
; 13. Fail the operation with the appropriate code. |
mov dword [esp+32], ERROR_ACCESS_DENIED |
.cleanup: |
; 14. Cleanup. |
mov esi, ecx ; disk*dereference assume that esi points to DISK |
.cleanup_esi: |
test edx, edx ; if there are no media, we didn't reference it |
jz @f |
call disk_media_dereference |
@@: |
call disk_dereference |
; 15. Return. |
ret |
; This is a callback for cleaning up things called from file_system_lfn.found2. |
dyndisk_cleanup: |
mov esi, [edi+8] |
mov edx, [edi+12] |
jmp dyndisk_handler.cleanup_esi |
; 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: |
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: |
pusha |
mov esi, ecx |
call disk_dereference |
popa |
stc |
ret |
; This is a callback for doing real work with selected partition. |
; Currently this is just placeholder, since no file systems are supported. |
; edi = esp -> {dd fs_dyndisk, dd dyndisk_cleanup, dd pointer to DISK, dd media object} |
; ecx = partition number, esi+ebp = ASCIIZ name |
fs_dyndisk: |
dec ecx ; convert to zero-based partition index |
pop edx edx edx eax ; edx = pointer to DISK, eax = NULL or edx |
test eax, eax |
jz .nomedia |
.main: |
cmp ecx, [edx+DISK.NumPartitions] |
jae .notfound |
mov eax, [edx+DISK.Partitions] |
mov eax, [eax+ecx*4] |
mov edi, [eax+PARTITION.FSUserFunctions] |
test edi, edi |
jz .nofs |
mov ecx, [ebx] |
cmp [edi], ecx |
jbe .unsupported |
push edx |
push ebp |
mov ebp, eax |
call dword [edi+4+ecx*4] |
pop ebp |
pop edx |
mov dword [esp+32], eax |
mov dword [esp+20], ebx |
.cleanup: |
mov esi, edx |
call disk_media_dereference |
call disk_dereference |
ret |
.nofs: |
mov dword [esp+32], ERROR_UNKNOWN_FS |
jmp .cleanup |
.notfound: |
mov dword [esp+32], ERROR_FILE_NOT_FOUND |
jmp .cleanup |
.unsupported: |
mov dword [esp+32], ERROR_UNSUPPORTED_FS |
jmp .cleanup |
.nomedia: |
test ecx, ecx |
jnz .notfound |
test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION |
jz .deverror |
; if the driver does not support insert notifications and we are the only fs |
; operation with this disk, issue the fake insert notification; if media is |
; still not inserted, 'disk_media_changed' will detect this and do nothing |
lea ecx, [edx+DISK.MediaLock] |
call mutex_lock |
cmp [edx+DISK.MediaRefCount], 1 |
jnz .noluck |
call mutex_unlock |
push edx |
stdcall disk_media_changed, edx, 1 |
pop edx |
lea ecx, [edx+DISK.MediaLock] |
call mutex_lock |
cmp [edx+DISK.MediaInserted], 0 |
jz .noluck |
lock inc [edx+DISK.MediaRefCount] |
call mutex_unlock |
xor ecx, ecx |
jmp .main |
.noluck: |
call mutex_unlock |
.deverror: |
mov dword [esp+32], ERROR_DEVICE |
mov esi, edx |
call disk_dereference |
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 |
/kernel/branches/net/blkdev/disk_cache.inc |
---|
0,0 → 1,645 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2381 $ |
; 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: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_read. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 0 |
call hd_read |
mov [hdd_appl_data], 1 ; restore to default state |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to SysCache and let the common part |
; do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.SysCache |
jmp fs_read32_common |
; 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: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_read. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 1 |
call hd_read |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to AppCache and let the common part |
; do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, 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 ecx |
ret |
@@: |
; 2. Get the absolute sector on the disk. |
push edx esi |
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 [ecx+DISKCACHE.pointer], 0 |
jnz .scancache |
push 1 |
push esp ; numsectors |
push edx ; startsector |
push eax ; startsector |
push ebx ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
pop ecx |
pop esi edx |
pop ecx |
ret |
.scancache: |
; 4. Scan the cache. |
push edi ecx ; scan cache |
push edx eax |
virtual at esp |
.sector_lo dd ? |
.sector_hi dd ? |
.cache dd ? |
end virtual |
; The following code is inherited from hd_read. The differences are: |
; all code is protected by the cache lock; instead of static calls |
; to hd_read_dma/hd_read_pio/bd_read the dynamic call to DISKFUNC.read is used; |
; sector is 64-bit, not 32-bit. |
call mutex_lock |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov esi, [ecx+DISKCACHE.pointer] |
mov ecx, [ecx+DISKCACHE.sad_size] |
add esi, 12 |
mov edi, 1 |
.hdreadcache: |
cmp dword [esi+8], 0 ; empty |
je .nohdcache |
cmp [esi], eax ; correct sector |
jne .nohdcache |
cmp [esi+4], edx ; correct sector |
je .yeshdcache |
.nohdcache: |
add esi, 12 |
inc edi |
dec ecx |
jnz .hdreadcache |
mov esi, [.cache] |
call find_empty_slot64 ; ret in edi |
test eax, eax |
jnz .read_done |
push 1 |
push esp |
push edx |
push [.sector_lo+12] |
mov ecx, [.cache+16] |
mov eax, edi |
shl eax, 9 |
add eax, [ecx+DISKCACHE.data] |
push eax |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.read |
call disk_call_driver |
pop ecx |
dec ecx |
jnz .read_done |
mov ecx, [.cache] |
lea eax, [edi*3] |
mov esi, [ecx+DISKCACHE.pointer] |
lea esi, [eax*4+esi] |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov [esi], eax ; sector number |
mov [esi+4], edx ; sector number |
mov dword [esi+8], 1; hd read - mark as same as in hd |
.yeshdcache: |
mov esi, edi |
mov ecx, [.cache] |
shl esi, 9 |
add esi, [ecx+DISKCACHE.data] |
mov edi, ebx |
mov ecx, 512/4 |
rep movsd ; move data |
xor eax, eax ; successful read |
.read_done: |
mov ecx, [.cache] |
push eax |
call mutex_unlock |
pop eax |
add esp, 12 |
pop edi esi edx ecx |
ret |
; 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: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_write. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 0 |
call hd_write |
mov [hdd_appl_data], 1 ; restore to default state |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to SysCache and let the common part |
; do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.SysCache |
jmp fs_write32_common |
; 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: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by hd_write. |
cmp [ebp+PARTITION.Disk], 'old' |
jnz @f |
add eax, dword [ebp+PARTITION.FirstSector] |
mov [hdd_appl_data], 1 |
call hd_write |
mov eax, [hd_error] |
ret |
@@: |
; In the normal case, save ecx, set ecx to AppCache and let the common part |
; do its work. |
push ecx |
mov ecx, [ebp+PARTITION.Disk] |
add ecx, DISK.AppCache |
; This label is the common part of fs_read32_sys and fs_read32_app. |
fs_write32_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 ecx |
ret |
@@: |
push edx esi |
; 2. Get the absolute sector on the disk. |
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 request to the driver. |
cmp [ecx+DISKCACHE.pointer], 0 |
jnz .scancache |
push 1 |
push esp ; numsectors |
push edx ; startsector |
push eax ; startsector |
push ebx ; buffer |
mov esi, [ebp+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
pop ecx |
pop esi edx |
pop ecx |
ret |
.scancache: |
; 4. Scan the cache. |
push edi ecx ; scan cache |
push edx eax |
virtual at esp |
.sector_lo dd ? |
.sector_hi dd ? |
.cache dd ? |
end virtual |
; The following code is inherited from hd_write. The differences are: |
; all code is protected by the cache lock; |
; sector is 64-bit, not 32-bit. |
call mutex_lock |
; check if the cache already has the sector and overwrite it |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov esi, [ecx+DISKCACHE.pointer] |
mov ecx, [ecx+DISKCACHE.sad_size] |
add esi, 12 |
mov edi, 1 |
.hdwritecache: |
cmp dword [esi+8], 0 ; if cache slot is empty |
je .not_in_cache_write |
cmp [esi], eax ; if the slot has the sector |
jne .not_in_cache_write |
cmp [esi+4], edx ; if the slot has the sector |
je .yes_in_cache_write |
.not_in_cache_write: |
add esi, 12 |
inc edi |
dec ecx |
jnz .hdwritecache |
; sector not found in cache |
; write the block to a new location |
mov esi, [.cache] |
call find_empty_slot64 ; ret in edi |
test eax, eax |
jne .hd_write_access_denied |
mov ecx, [.cache] |
lea eax, [edi*3] |
mov esi, [ecx+DISKCACHE.pointer] |
lea esi, [eax*4+esi] |
mov eax, [.sector_lo] |
mov edx, [.sector_hi] |
mov [esi], eax ; sector number |
mov [esi+4], edx ; sector number |
.yes_in_cache_write: |
mov dword [esi+8], 2 ; write - differs from hd |
shl edi, 9 |
mov ecx, [.cache] |
add edi, [ecx+DISKCACHE.data] |
mov esi, ebx |
mov ecx, 512/4 |
rep movsd ; move data |
xor eax, eax ; success |
.hd_write_access_denied: |
mov ecx, [.cache] |
push eax |
call mutex_unlock |
pop eax |
add esp, 12 |
pop edi esi edx ecx |
ret |
; This internal function is called from fs_read32_* and fs_write32_*. It is the |
; analogue of find_empty_slot for 64-bit sectors. |
find_empty_slot64: |
;----------------------------------------------------------- |
; find empty or read slot, flush cache if next 12.5% is used by write |
; output : edi = cache slot |
;----------------------------------------------------------- |
.search_again: |
mov ecx, [esi+DISKCACHE.sad_size] |
mov edi, [esi+DISKCACHE.search_start] |
shr ecx, 3 |
.search_for_empty: |
inc edi |
cmp edi, [esi+DISKCACHE.sad_size] |
jbe .inside_cache |
mov edi, 1 |
.inside_cache: |
lea eax, [edi*3] |
shl eax, 2 |
add eax, [esi+DISKCACHE.pointer] |
cmp dword [eax+8], 2 |
jb .found_slot ; it's empty or read |
dec ecx |
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 [esi+DISKCACHE.search_start], edi |
xor eax, eax ; success |
.found_slot_access_denied: |
ret |
; This function is intended to replace the old 'write_cache' function. |
proc write_cache64 uses ecx edx esi edi, disk:dword |
locals |
cache_chain_started dd 0 |
cache_chain_size dd ? |
cache_chain_pos dd ? |
cache_chain_ptr dd ? |
endl |
saved_esi_pos = 16+12 ; size of local variables + size of registers before esi |
; If there is no cache for this disk, nothing to do. |
cmp [esi+DISKCACHE.pointer], 0 |
jz .flush |
;----------------------------------------------------------- |
; write all changed sectors to disk |
;----------------------------------------------------------- |
; write difference ( 2 ) from cache to DISK |
mov ecx, [esi+DISKCACHE.sad_size] |
mov esi, [esi+DISKCACHE.pointer] |
add esi, 12 |
mov edi, 1 |
.write_cache_more: |
cmp dword [esi+8], 2 ; if cache slot is not different |
jne .write_chain |
mov dword [esi+8], 1 ; same as in hd |
mov eax, [esi] |
mov edx, [esi+4] ; edx:eax = sector to write |
; Îáúåäèíÿåì çàïèñü öåïî÷êè ïîñëåäîâàòåëüíûõ ñåêòîðîâ â îäíî îáðàùåíèå ê äèñêó |
cmp ecx, 1 |
jz .nonext |
cmp dword [esi+12+8], 2 |
jnz .nonext |
push eax edx |
add eax, 1 |
adc edx, 0 |
cmp eax, [esi+12] |
jnz @f |
cmp edx, [esi+12+4] |
@@: |
pop edx eax |
jnz .nonext |
cmp [cache_chain_started], 1 |
jz @f |
mov [cache_chain_started], 1 |
mov [cache_chain_size], 0 |
mov [cache_chain_pos], edi |
mov [cache_chain_ptr], esi |
@@: |
inc [cache_chain_size] |
cmp [cache_chain_size], 16 |
jnz .continue |
jmp .write_chain |
.nonext: |
call .flush_cache_chain |
test eax, eax |
jnz .nothing |
mov [cache_chain_size], 1 |
mov [cache_chain_ptr], esi |
call .write_cache_sector |
test eax, eax |
jnz .nothing |
jmp .continue |
.write_chain: |
call .flush_cache_chain |
test eax, eax |
jnz .nothing |
.continue: |
add esi, 12 |
inc edi |
dec ecx |
jnz .write_cache_more |
call .flush_cache_chain |
test eax, eax |
jnz .nothing |
.flush: |
mov esi, [disk] |
mov al, DISKFUNC.flush |
call disk_call_driver |
.nothing: |
ret |
.flush_cache_chain: |
xor eax, eax |
cmp [cache_chain_started], eax |
jz @f |
call .write_cache_chain |
mov [cache_chain_started], 0 |
@@: |
retn |
.write_cache_sector: |
mov [cache_chain_size], 1 |
mov [cache_chain_pos], edi |
.write_cache_chain: |
pusha |
mov edi, [cache_chain_pos] |
mov ecx, [ebp-saved_esi_pos] |
shl edi, 9 |
add edi, [ecx+DISKCACHE.data] |
mov ecx, [cache_chain_size] |
push ecx |
push esp ; numsectors |
mov eax, [cache_chain_ptr] |
pushd [eax+4] |
pushd [eax] ; startsector |
push edi ; buffer |
mov esi, [ebp] |
mov esi, [esi+PARTITION.Disk] |
mov al, DISKFUNC.write |
call disk_call_driver |
pop ecx |
mov [esp+28], eax |
popa |
retn |
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. Calculate the suggested cache size. |
; 1a. Get the size of free physical memory in pages. |
mov eax, [pg_data.pages_free] |
; 1b. 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 |
; 1c. 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 |
@@: |
; 1d. 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 |
; 2. Allocate memory for the cache. |
; 2a. Call the allocator. |
stdcall kernel_alloc, eax |
test eax, eax |
jnz @f |
; 2b. If it failed, say a message and return with eax = 0. |
dbgstr 'no memory for disk cache' |
jmp .nothing |
@@: |
; 3. Fill two DISKCACHE structures. |
mov [esi+DISK.SysCache.pointer], eax |
lea ecx, [esi+DISK.SysCache.mutex] |
call mutex_init |
lea ecx, [esi+DISK.AppCache.mutex] |
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] |
push ebx |
call calculate_for_hd64 |
pop ebx |
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*3] |
xor eax, eax |
rep stosd |
pop edi |
mov eax, [esi+DISK.AppCache.data_size] |
push ebx |
call calculate_for_hd64 |
pop ebx |
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*3] |
xor eax, eax |
rep stosd |
pop edi |
; 4. Return with nonzero al. |
mov al, 1 |
; 5. 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_for_hd64: |
push eax |
mov ebx, eax |
shr eax, 9 |
lea eax, [eax*3] |
shl eax, 2 |
sub ebx, eax |
shr ebx, 9 |
mov ecx, ebx |
shl ebx, 9 |
pop eax |
sub eax, ebx |
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: |
; Compatibility hack: if PARTITION.Disk is 'old', there is no DISK structure, |
; this request should be processed by write_cache. |
cmp esi, 'old' |
jnz @f |
mov [hdd_appl_data], 0 |
call write_cache |
mov [hdd_appl_data], 1 |
call write_cache |
mov eax, [hd_error] |
ret |
@@: |
; The algorithm is straightforward. |
push esi |
push esi ; for second write_cache64 |
push esi ; for first write_cache64 |
add esi, DISK.SysCache |
call write_cache64 |
add esi, DISK.AppCache - DISK.SysCache |
call write_cache64 |
pop esi |
ret |
/kernel/branches/net/blkdev/hd_drv.inc |
---|
0,0 → 1,1047 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
; Low-level driver for HDD access |
; DMA support by Mario79 |
; Access through BIOS by diamond |
align 4 |
hd_read: |
;----------------------------------------------------------- |
; input : eax = block to read |
; ebx = destination |
;----------------------------------------------------------- |
and [hd_error], 0 |
push ecx esi edi ; scan cache |
; mov ecx,cache_max ; entries in cache |
; mov esi,HD_CACHE+8 |
call calculate_cache |
add esi, 8 |
mov edi, 1 |
hdreadcache: |
cmp dword [esi+4], 0; empty |
je nohdcache |
cmp [esi], eax ; correct sector |
je yeshdcache |
nohdcache: |
add esi, 8 |
inc edi |
dec ecx |
jnz hdreadcache |
call find_empty_slot ; ret in edi |
cmp [hd_error], 0 |
jne return_01 |
; Read through BIOS? |
cmp [hdpos], 0x80 |
jae .bios |
; hd_read_{dma,pio} use old ATA with 28 bit for sector number |
cmp eax, 0x10000000 |
jb @f |
inc [hd_error] |
jmp return_01 |
@@: |
; DMA read is permitted if [allow_dma_access]=1 or 2 |
cmp [allow_dma_access], 2 |
ja .nodma |
cmp [dma_hdd], 1 |
jnz .nodma |
call hd_read_dma |
jmp @f |
.nodma: |
call hd_read_pio |
jmp @f |
.bios: |
call bd_read |
@@: |
cmp [hd_error], 0 |
jne return_01 |
; lea esi,[edi*8+HD_CACHE] |
; push eax |
call calculate_cache_1 |
lea esi, [edi*8+esi] |
; pop eax |
mov [esi], eax ; sector number |
mov dword [esi+4], 1; hd read - mark as same as in hd |
yeshdcache: |
mov esi, edi |
shl esi, 9 |
; add esi,HD_CACHE+65536 |
push eax |
call calculate_cache_2 |
add esi, eax |
pop eax |
mov edi, ebx |
mov ecx, 512/4 |
cld |
rep movsd ; move data |
return_01: |
pop edi esi ecx |
ret |
align 4 |
hd_read_pio: |
push eax edx |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jne hd_read_error |
cli |
xor eax, eax |
mov edx, [hdbase] |
inc edx |
out dx, al; ATAFeatures ॣ¨áâà "®á®¡¥®á⥩" |
inc edx |
inc eax |
out dx, al; ATASectorCount áçñâ稪 ᥪâ®à®¢ |
inc edx |
mov eax, [esp+4] |
out dx, al; ATASectorNumber ॣ¨áâà ®¬¥à ᥪâ®à |
shr eax, 8 |
inc edx |
out dx, al; ATACylinder ®¬¥à 樫¨¤à (¬« ¤è¨© ¡ ©â) |
shr eax, 8 |
inc edx |
out dx, al; ®¬¥à 樫¨¤à (áâ à訩 ¡ ©â) |
shr eax, 8 |
inc edx |
and al, 1+2+4+8 |
add al, byte [hdid] |
add al, 128+64+32 |
out dx, al; ®¬¥à £®«®¢ª¨/®¬¥à ¤¨áª |
inc edx |
mov al, 20h |
out dx, al; ATACommand ॣ¨áâà ª®¬ ¤ |
sti |
call wait_for_sector_buffer |
cmp [hd_error], 0 |
jne hd_read_error |
cli |
push edi |
shl edi, 9 |
; add edi,HD_CACHE+65536 |
push eax |
call calculate_cache_2 |
add edi, eax |
pop eax |
mov ecx, 256 |
mov edx, [hdbase] |
cld |
rep insw |
pop edi |
sti |
pop edx eax |
ret |
disable_ide_int: |
; mov edx,[hdbase] |
; add edx,0x206 |
; mov al,2 |
; out dx,al |
cli |
ret |
enable_ide_int: |
; mov edx,[hdbase] |
; add edx,0x206 |
; mov al,0 |
; out dx,al |
sti |
ret |
align 4 |
hd_write: |
;----------------------------------------------------------- |
; input : eax = block |
; ebx = pointer to memory |
;----------------------------------------------------------- |
push ecx esi edi |
; check if the cache already has the sector and overwrite it |
; mov ecx,cache_max |
; mov esi,HD_CACHE+8 |
call calculate_cache |
add esi, 8 |
mov edi, 1 |
hdwritecache: |
cmp dword [esi+4], 0; if cache slot is empty |
je not_in_cache_write |
cmp [esi], eax ; if the slot has the sector |
je yes_in_cache_write |
not_in_cache_write: |
add esi, 8 |
inc edi |
dec ecx |
jnz hdwritecache |
; sector not found in cache |
; write the block to a new location |
call find_empty_slot ; ret in edi |
cmp [hd_error], 0 |
jne hd_write_access_denied |
; lea esi,[edi*8+HD_CACHE] |
; push eax |
call calculate_cache_1 |
lea esi, [edi*8+esi] |
; pop eax |
mov [esi], eax ; sector number |
yes_in_cache_write: |
mov dword [esi+4], 2; write - differs from hd |
shl edi, 9 |
; add edi,HD_CACHE+65536 |
push eax |
call calculate_cache_2 |
add edi, eax |
pop eax |
mov esi, ebx |
mov ecx, 512/4 |
cld |
rep movsd ; move data |
hd_write_access_denied: |
pop edi esi ecx |
ret |
align 4 |
cache_write_pio: |
cmp dword[esi], 0x10000000 |
jae .bad |
; call disable_ide_int |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jne hd_write_error |
cli |
xor eax, eax |
mov edx, [hdbase] |
inc edx |
out dx, al |
inc edx |
inc eax |
out dx, al |
inc edx |
mov eax, [esi] ; eax = sector to write |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
and al, 1+2+4+8 |
add al, byte [hdid] |
add al, 128+64+32 |
out dx, al |
inc edx |
mov al, 30h |
out dx, al |
sti |
call wait_for_sector_buffer |
cmp [hd_error], 0 |
jne hd_write_error |
push ecx esi |
cli |
mov esi, edi |
shl esi, 9 |
; add esi,HD_CACHE+65536 ; esi = from memory position |
push eax |
call calculate_cache_2 |
add esi, eax |
pop eax |
mov ecx, 256 |
mov edx, [hdbase] |
cld |
rep outsw |
sti |
; call enable_ide_int |
pop esi ecx |
ret |
.bad: |
inc [hd_error] |
ret |
save_hd_wait_timeout: |
push eax |
mov eax, [timer_ticks] |
add eax, 300 ; 3 sec timeout |
mov [hd_wait_timeout], eax |
pop eax |
ret |
align 4 |
check_hd_wait_timeout: |
push eax |
mov eax, [hd_wait_timeout] |
cmp [timer_ticks], eax |
jg hd_timeout_error |
pop eax |
mov [hd_error], 0 |
ret |
;iglobal |
; hd_timeout_str db 'K : FS - HD timeout',0 |
; hd_read_str db 'K : FS - HD read error',0 |
; hd_write_str db 'K : FS - HD write error',0 |
; hd_lba_str db 'K : FS - HD LBA error',0 |
;endg |
hd_timeout_error: |
; call clear_hd_cache |
; call clear_application_table_status |
; mov esi,hd_timeout_str |
; call sys_msg_board_str |
if lang eq sp |
DEBUGF 1,"K : FS - HD tiempo de espera agotado\n" |
else |
DEBUGF 1,"K : FS - HD timeout\n" |
end if |
mov [hd_error], 1 |
pop eax |
ret |
hd_read_error: |
; call clear_hd_cache |
; call clear_application_table_status |
; mov esi,hd_read_str |
; call sys_msg_board_str |
if lang eq sp |
DEBUGF 1,"K : FS - HD error de lectura\n" |
else |
DEBUGF 1,"K : FS - HD read error\n" |
end if |
pop edx eax |
ret |
hd_write_error: |
; call clear_hd_cache |
; call clear_application_table_status |
; mov esi,hd_write_str |
; call sys_msg_board_str |
if lang eq sp |
DEBUGF 1,"K : FS - HD error de escritura\n" |
else |
DEBUGF 1,"K : FS - HD write error\n" |
end if |
ret |
hd_write_error_dma: |
; call clear_hd_cache |
; call clear_application_table_status |
; mov esi, hd_write_str |
; call sys_msg_board_str |
if lang eq sp |
DEBUGF 1,"K : FS - HD error de escritura\n" |
else |
DEBUGF 1,"K : FS - HD write error\n" |
end if |
pop esi |
ret |
hd_lba_error: |
; call clear_hd_cache |
; call clear_application_table_status |
; mov esi,hd_lba_str |
; call sys_msg_board_str |
if lang eq sp |
DEBUGF 1,"K : FS - HD error en LBA\n" |
else |
DEBUGF 1,"K : FS - HD LBA error\n" |
end if |
jmp LBA_read_ret |
align 4 |
wait_for_hd_idle: |
push eax edx |
call save_hd_wait_timeout |
mov edx, [hdbase] |
add edx, 0x7 |
wfhil1: |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jne @f |
in al, dx |
test al, 128 |
jnz wfhil1 |
@@: |
pop edx eax |
ret |
align 4 |
wait_for_sector_buffer: |
push eax edx |
mov edx, [hdbase] |
add edx, 0x7 |
call save_hd_wait_timeout |
hdwait_sbuf: ; wait for sector buffer to be ready |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jne @f |
in al, dx |
test al, 8 |
jz hdwait_sbuf |
mov [hd_error], 0 |
cmp [hd_setup], 1 ; do not mark error for setup request |
je buf_wait_ok |
test al, 1 ; previous command ended up with an error |
jz buf_wait_ok |
@@: |
mov [hd_error], 1 |
buf_wait_ok: |
pop edx eax |
ret |
; \begin{Mario79} |
align 4 |
wait_for_sector_dma_ide0: |
push eax |
push edx |
call save_hd_wait_timeout |
.wait: |
call change_task |
cmp [irq14_func], hdd_irq14 |
jnz .done |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jz .wait |
mov [irq14_func], hdd_irq_null |
mov dx, [IDEContrRegsBaseAddr] |
mov al, 0 |
out dx, al |
.done: |
pop edx |
pop eax |
ret |
align 4 |
wait_for_sector_dma_ide1: |
push eax |
push edx |
call save_hd_wait_timeout |
.wait: |
call change_task |
cmp [irq15_func], hdd_irq15 |
jnz .done |
call check_hd_wait_timeout |
cmp [hd_error], 0 |
jz .wait |
mov [irq15_func], hdd_irq_null |
mov dx, [IDEContrRegsBaseAddr] |
add dx, 8 |
mov al, 0 |
out dx, al |
.done: |
pop edx |
pop eax |
ret |
iglobal |
align 4 |
; note that IDE descriptor table must be 4-byte aligned and do not cross 4K boundary |
IDE_descriptor_table: |
dd IDE_DMA |
dw 0x2000 |
dw 0x8000 |
dma_cur_sector dd not 40h |
dma_hdpos dd 0 |
irq14_func dd hdd_irq_null |
irq15_func dd hdd_irq_null |
endg |
uglobal |
; all uglobals are zeroed at boot |
dma_process dd 0 |
dma_slot_ptr dd 0 |
cache_chain_pos dd 0 |
cache_chain_ptr dd 0 |
cache_chain_size db 0 |
cache_chain_started db 0 |
dma_task_switched db 0 |
dma_hdd db 0 |
allow_dma_access db 0 |
endg |
align 4 |
hdd_irq14: |
pushfd |
cli |
pushad |
mov [irq14_func], hdd_irq_null |
mov dx, [IDEContrRegsBaseAddr] |
mov al, 0 |
out dx, al |
; call update_counters |
; mov ebx, [dma_process] |
; cmp [CURRENT_TASK], ebx |
; jz .noswitch |
; mov [dma_task_switched], 1 |
; mov edi, [dma_slot_ptr] |
; mov eax, [CURRENT_TASK] |
; mov [dma_process], eax |
; mov eax, [TASK_BASE] |
; mov [dma_slot_ptr], eax |
; mov [CURRENT_TASK], ebx |
; mov [TASK_BASE], edi |
; mov byte [DONT_SWITCH], 1 |
; call do_change_task |
.noswitch: |
popad |
popfd |
align 4 |
hdd_irq_null: |
ret |
align 4 |
hdd_irq15: |
pushfd |
cli |
pushad |
mov [irq15_func], hdd_irq_null |
mov dx, [IDEContrRegsBaseAddr] |
add dx, 8 |
mov al, 0 |
out dx, al |
; call update_counters |
; mov ebx, [dma_process] |
; cmp [CURRENT_TASK], ebx |
; jz .noswitch |
; mov [dma_task_switched], 1 |
; mov edi, [dma_slot_ptr] |
; mov eax, [CURRENT_TASK] |
; mov [dma_process], eax |
; mov eax, [TASK_BASE] |
; mov [dma_slot_ptr], eax |
; mov [CURRENT_TASK], ebx |
; mov [TASK_BASE], edi |
; mov byte [DONT_SWITCH], 1 |
; call do_change_task |
.noswitch: |
popad |
popfd |
ret |
align 4 |
hd_read_dma: |
push eax |
push edx |
mov edx, [dma_hdpos] |
cmp edx, [hdpos] |
jne .notread |
mov edx, [dma_cur_sector] |
cmp eax, edx |
jb .notread |
add edx, 15 |
cmp [esp+4], edx |
ja .notread |
mov eax, [esp+4] |
sub eax, [dma_cur_sector] |
shl eax, 9 |
add eax, (OS_BASE+IDE_DMA) |
push ecx esi edi |
mov esi, eax |
shl edi, 9 |
; add edi, HD_CACHE+0x10000 |
push eax |
call calculate_cache_2 |
add edi, eax |
pop eax |
mov ecx, 512/4 |
cld |
rep movsd |
pop edi esi ecx |
pop edx |
pop eax |
ret |
.notread: |
mov eax, IDE_descriptor_table |
mov dword [eax], IDE_DMA |
mov word [eax+4], 0x2000 |
sub eax, OS_BASE |
mov dx, [IDEContrRegsBaseAddr] |
cmp [hdbase], 0x1F0 |
jz @f |
add edx, 8 |
@@: |
push edx |
add edx, 4 |
out dx, eax |
pop edx |
mov al, 0 |
out dx, al |
add edx, 2 |
mov al, 6 |
out dx, al |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jnz hd_read_error |
call disable_ide_int |
xor eax, eax |
mov edx, [hdbase] |
inc edx |
out dx, al |
inc edx |
mov eax, 10h |
out dx, al |
inc edx |
mov eax, [esp+4] |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
and al, 0xF |
add al, byte [hdid] |
add al, 11100000b |
out dx, al |
inc edx |
mov al, 0xC8 |
out dx, al |
mov dx, [IDEContrRegsBaseAddr] |
cmp [hdbase], 0x1F0 |
jz @f |
add dx, 8 |
@@: |
mov al, 9 |
out dx, al |
mov eax, [CURRENT_TASK] |
mov [dma_process], eax |
mov eax, [TASK_BASE] |
mov [dma_slot_ptr], eax |
cmp [hdbase], 0x1F0 |
jnz .ide1 |
mov [irq14_func], hdd_irq14 |
jmp @f |
.ide1: |
mov [irq15_func], hdd_irq15 |
@@: |
call enable_ide_int |
cmp [hdbase], 0x1F0 |
jnz .wait_ide1 |
call wait_for_sector_dma_ide0 |
jmp @f |
.wait_ide1: |
call wait_for_sector_dma_ide1 |
@@: |
cmp [hd_error], 0 |
jnz hd_read_error |
mov eax, [hdpos] |
mov [dma_hdpos], eax |
pop edx |
pop eax |
mov [dma_cur_sector], eax |
jmp hd_read_dma |
align 4 |
write_cache_sector: |
mov [cache_chain_size], 1 |
mov [cache_chain_pos], edi |
write_cache_chain: |
cmp [hdpos], 0x80 |
jae bd_write_cache_chain |
mov eax, [cache_chain_ptr] |
cmp dword[eax], 0x10000000 |
jae .bad |
push esi |
mov eax, IDE_descriptor_table |
mov edx, eax |
pusha |
mov esi, [cache_chain_pos] |
shl esi, 9 |
call calculate_cache_2 |
add esi, eax |
mov edi, (OS_BASE+IDE_DMA) |
mov dword [edx], IDE_DMA |
movzx ecx, [cache_chain_size] |
shl ecx, 9 |
mov word [edx+4], cx |
shr ecx, 2 |
cld |
rep movsd |
popa |
sub eax, OS_BASE |
mov dx, [IDEContrRegsBaseAddr] |
cmp [hdbase], 0x1F0 |
jz @f |
add edx, 8 |
@@: |
push edx |
add edx, 4 |
out dx, eax |
pop edx |
mov al, 0 |
out dx, al |
add edx, 2 |
mov al, 6 |
out dx, al |
call wait_for_hd_idle |
cmp [hd_error], 0 |
jnz hd_write_error_dma |
call disable_ide_int |
xor eax, eax |
mov edx, [hdbase] |
inc edx |
out dx, al |
inc edx |
mov al, [cache_chain_size] |
out dx, al |
inc edx |
mov esi, [cache_chain_ptr] |
mov eax, [esi] |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
out dx, al |
shr eax, 8 |
inc edx |
and al, 0xF |
add al, byte [hdid] |
add al, 11100000b |
out dx, al |
inc edx |
mov al, 0xCA |
out dx, al |
mov dx, [IDEContrRegsBaseAddr] |
cmp [hdbase], 0x1F0 |
jz @f |
add dx, 8 |
@@: |
mov al, 1 |
out dx, al |
mov eax, [CURRENT_TASK] |
mov [dma_process], eax |
mov eax, [TASK_BASE] |
mov [dma_slot_ptr], eax |
cmp [hdbase], 0x1F0 |
jnz .ide1 |
mov [irq14_func], hdd_irq14 |
jmp @f |
.ide1: |
mov [irq15_func], hdd_irq15 |
@@: |
call enable_ide_int |
mov [dma_cur_sector], not 0x40 |
cmp [hdbase], 0x1F0 |
jnz .wait_ide1 |
call wait_for_sector_dma_ide0 |
jmp @f |
.wait_ide1: |
call wait_for_sector_dma_ide1 |
@@: |
cmp [hd_error], 0 |
jnz hd_write_error_dma |
pop esi |
ret |
.bad: |
inc [hd_error] |
ret |
uglobal |
IDEContrRegsBaseAddr dw ? |
endg |
; \end{Mario79} |
; \begin{diamond} |
uglobal |
bios_hdpos dd 0 ; 0 is invalid value for [hdpos] |
bios_cur_sector dd ? |
bios_read_len dd ? |
endg |
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+0x9A000) |
push ecx esi edi |
mov esi, eax |
shl edi, 9 |
; add edi, HD_CACHE+0x10000 |
push eax |
call calculate_cache_2 |
add edi, eax |
pop eax |
mov ecx, 512/4 |
cld |
rep movsd |
pop edi 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: |
mov [hd_error], 1 |
jmp hd_read_error |
bd_write_cache_chain: |
pusha |
mov esi, [cache_chain_pos] |
shl esi, 9 |
call calculate_cache_2 |
add esi, eax |
mov edi, OS_BASE + 0x9A000 |
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 |
uglobal |
int13_regs_in rb sizeof.v86_regs |
int13_regs_out rb sizeof.v86_regs |
endg |
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 'hd1_status' |
mov word [OS_BASE + 510h], 10h ; packet length |
mov word [OS_BASE + 512h], cx ; number of sectors |
mov dword [OS_BASE + 514h], 9A000000h ; buffer 9A00: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, [BiosDisksData+(eax-80h)*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], 0A000h |
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 |
; \end{diamond} |
reserve_hd1: |
cli |
cmp [hd1_status], 0 |
je reserve_ok1 |
sti |
call change_task |
jmp reserve_hd1 |
reserve_ok1: |
push eax |
mov eax, [CURRENT_TASK] |
shl eax, 5 |
mov eax, [eax+CURRENT_TASK+TASKDATA.pid] |
mov [hd1_status], eax |
pop eax |
sti |
ret |
;******************************************** |
uglobal |
hd_in_cache db ? |
endg |
reserve_hd_channel: |
; BIOS disk accesses are protected with common mutex hd1_status |
; This must be modified when hd1_status will not be valid! |
cmp [hdpos], 0x80 |
jae .ret |
cmp [hdbase], 0x1F0 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
cli |
cmp [IDE_Channel_1], 0 |
je .reserve_ok_1 |
sti |
call change_task |
jmp .IDE_Channel_1 |
.IDE_Channel_2: |
cli |
cmp [IDE_Channel_2], 0 |
je .reserve_ok_2 |
sti |
call change_task |
jmp .IDE_Channel_2 |
.reserve_ok_1: |
mov [IDE_Channel_1], 1 |
push eax |
mov al, 1 |
jmp @f |
.reserve_ok_2: |
mov [IDE_Channel_2], 1 |
push eax |
mov al, 3 |
@@: |
cmp [hdid], 1 |
sbb al, -1 |
mov [hd_in_cache], al |
pop eax |
sti |
.ret: |
ret |
free_hd_channel: |
; see comment at reserve_hd_channel |
cmp [hdpos], 0x80 |
jae .ret |
cmp [hdbase], 0x1F0 |
jne .IDE_Channel_2 |
.IDE_Channel_1: |
mov [IDE_Channel_1], 0 |
.ret: |
ret |
.IDE_Channel_2: |
mov [IDE_Channel_2], 0 |
ret |
;******************************************** |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/ide_cache.inc |
---|
0,0 → 1,920 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 |
write_cache: |
;----------------------------------------------------------- |
; write all changed sectors to disk |
;----------------------------------------------------------- |
push eax ecx edx esi edi |
; write difference ( 2 ) from cache to hd |
call calculate_cache |
add esi, 8 |
mov edi, 1 |
write_cache_more: |
cmp dword [esi+4], 2; if cache slot is not different |
jne .write_chain |
mov dword [esi+4], 1; same as in hd |
mov eax, [esi] ; eax = sector to write |
cmp eax, [PARTITION_START] |
jb danger |
cmp eax, [PARTITION_END] |
ja danger |
cmp [hdpos], 0x80 |
jae @f |
; DMA write is permitted only if [allow_dma_access]=1 |
cmp [allow_dma_access], 2 |
jae .nodma |
cmp [dma_hdd], 1 |
jnz .nodma |
@@: |
; ¡ê¥¤¨ï¥¬ § ¯¨áì 楯®çª¨ ¯®á«¥¤®¢ ⥫ìëå ᥪâ®à®¢ ¢ ®¤® ®¡à 饨¥ ª ¤¨áªã |
cmp ecx, 1 |
jz .nonext |
cmp dword [esi+8+4], 2 |
jnz .nonext |
push eax |
inc eax |
cmp eax, [esi+8] |
pop eax |
jnz .nonext |
cmp [cache_chain_started], 1 |
jz @f |
mov [cache_chain_started], 1 |
mov [cache_chain_size], 0 |
mov [cache_chain_pos], edi |
mov [cache_chain_ptr], esi |
@@: |
inc [cache_chain_size] |
cmp [cache_chain_size], 16 |
jnz .continue |
jmp .write_chain |
.nonext: |
call flush_cache_chain |
mov [cache_chain_size], 1 |
mov [cache_chain_ptr], esi |
call write_cache_sector |
jmp .continue |
.nodma: |
call cache_write_pio |
.write_chain: |
call flush_cache_chain |
.continue: |
danger: |
add esi, 8 |
inc edi |
dec ecx |
jnz write_cache_more |
call flush_cache_chain |
return_02: |
pop edi esi edx ecx eax |
ret |
flush_cache_chain: |
cmp [cache_chain_started], 0 |
jz @f |
call write_cache_chain |
mov [cache_chain_started], 0 |
@@: |
ret |
;-------------------------------------------------------------------- |
align 4 |
find_empty_slot: |
;----------------------------------------------------------- |
; find empty or read slot, flush cache if next 10% is used by write |
; output : edi = cache slot |
;----------------------------------------------------------- |
; push ecx esi |
search_again: |
call calculate_cache_3 |
shr ecx, 3 |
search_for_empty: |
inc edi |
call calculate_cache_4 |
jbe inside_cache |
mov edi, 1 |
inside_cache: |
push esi |
call calculate_cache_1 |
cmp dword [edi*8+esi+4], 2 |
pop esi |
jb found_slot ; it's empty or read |
dec ecx |
jnz search_for_empty |
call write_cache ; no empty slots found, write all |
cmp [hd_error], 0 |
jne found_slot_access_denied |
jmp search_again ; and start again |
found_slot: |
call calculate_cache_5 |
found_slot_access_denied: |
ret |
;-------------------------------------------------------------------- |
align 4 |
clear_hd_cache: |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache: |
; mov ecx,cache_max ; entries in cache |
; mov esi,HD_CACHE+8 |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov ecx, [cache_ide1_system_sad_size] |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov ecx, [cache_ide1_appl_sad_size] |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov ecx, [cache_ide2_system_sad_size] |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov ecx, [cache_ide2_appl_sad_size] |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov ecx, [cache_ide3_system_sad_size] |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov ecx, [cache_ide3_appl_sad_size] |
mov esi, [cache_ide3_data_pointer] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov ecx, [cache_ide0_system_sad_size-cache_ide0+eax] |
mov esi, [cache_ide0_pointer-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov ecx, [cache_ide0_appl_sad_size-cache_ide0+eax] |
mov esi, [cache_ide0_data_pointer-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_1: |
; lea esi,[edi*8+HD_CACHE] |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov esi, [cache_ide3_data_pointer] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov esi, [cache_ide0_pointer-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov esi, [cache_ide0_data_pointer-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_2: |
; add esi,HD_CACHE+65536 |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov eax, [cache_ide0_system_data] |
ret |
.ide0_appl_data: |
mov eax, [cache_ide0_appl_data] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov eax, [cache_ide1_system_data] |
ret |
.ide1_appl_data: |
mov eax, [cache_ide1_appl_data] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov eax, [cache_ide2_system_data] |
ret |
.ide2_appl_data: |
mov eax, [cache_ide2_appl_data] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov eax, [cache_ide3_system_data] |
ret |
.ide3_appl_data: |
mov eax, [cache_ide3_appl_data] |
ret |
.noide: |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov eax, [cache_ide0_system_data-cache_ide0+eax] |
ret |
.bd_appl_data: |
mov eax, [cache_ide0_appl_data-cache_ide0+eax] |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_3: |
; mov ecx,cache_max*10/100 |
; mov edi,[cache_search_start] |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov edi, [cache_ide0_search_start] |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov edi, [cache_ide0_appl_search_start] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov ecx, [cache_ide1_system_sad_size] |
mov edi, [cache_ide1_search_start] |
ret |
.ide1_appl_data: |
mov ecx, [cache_ide1_appl_sad_size] |
mov edi, [cache_ide1_appl_search_start] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov ecx, [cache_ide2_system_sad_size] |
mov edi, [cache_ide2_search_start] |
ret |
.ide2_appl_data: |
mov ecx, [cache_ide2_appl_sad_size] |
mov edi, [cache_ide2_appl_search_start] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov ecx, [cache_ide3_system_sad_size] |
mov edi, [cache_ide3_search_start] |
ret |
.ide3_appl_data: |
mov ecx, [cache_ide3_appl_sad_size] |
mov edi, [cache_ide3_appl_search_start] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov ecx, [cache_ide0_system_sad_size-cache_ide0+eax] |
mov edi, [cache_ide0_search_start-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
mov ecx, [cache_ide0_appl_sad_size-cache_ide0+eax] |
mov edi, [cache_ide0_appl_search_start-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_4: |
; cmp edi,cache_max |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
cmp edi, [cache_ide0_system_sad_size] |
ret |
.ide0_appl_data: |
cmp edi, [cache_ide0_appl_sad_size] |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
cmp edi, [cache_ide1_system_sad_size] |
ret |
.ide1_appl_data: |
cmp edi, [cache_ide1_appl_sad_size] |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
cmp edi, [cache_ide2_system_sad_size] |
ret |
.ide2_appl_data: |
cmp edi, [cache_ide2_appl_sad_size] |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
cmp edi, [cache_ide3_system_sad_size] |
ret |
.ide3_appl_data: |
cmp edi, [cache_ide3_appl_sad_size] |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
cmp edi, [cache_ide0_system_sad_size-cache_ide0+eax] |
pop eax |
ret |
.bd_appl_data: |
cmp edi, [cache_ide0_appl_sad_size-cache_ide0+eax] |
pop eax |
ret |
;-------------------------------------------------------------------- |
align 4 |
calculate_cache_5: |
; mov [cache_search_start],edi |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [hdpos], 1 |
jne .ide1 |
cmp [hdd_appl_data], 0 |
jne .ide0_appl_data |
mov [cache_ide0_search_start], edi |
ret |
.ide0_appl_data: |
mov [cache_ide0_appl_search_start], edi |
ret |
.ide1: |
cmp [hdpos], 2 |
jne .ide2 |
cmp [hdd_appl_data], 0 |
jne .ide1_appl_data |
mov [cache_ide1_search_start], edi |
ret |
.ide1_appl_data: |
mov [cache_ide1_appl_search_start], edi |
ret |
.ide2: |
cmp [hdpos], 3 |
jne .ide3 |
cmp [hdd_appl_data], 0 |
jne .ide2_appl_data |
mov [cache_ide2_search_start], edi |
ret |
.ide2_appl_data: |
mov [cache_ide2_appl_search_start], edi |
ret |
.ide3: |
cmp [hdpos], 4 |
jne .noide |
cmp [hdd_appl_data], 0 |
jne .ide3_appl_data |
mov [cache_ide3_search_start], edi |
ret |
.ide3_appl_data: |
mov [cache_ide3_appl_search_start], edi |
ret |
.noide: |
push eax |
mov eax, [hdpos] |
sub eax, 80h |
cmp byte [BiosDisksData+eax*4+2], -1 |
jz @f |
movzx eax, byte [BiosDisksData+eax*4+2] |
imul eax, cache_ide1-cache_ide0 |
add eax, cache_ide0 |
jmp .get |
@@: |
imul eax, cache_ide1-cache_ide0 |
add eax, BiosDiskCaches |
.get: |
cmp [hdd_appl_data], 0 |
jne .bd_appl_data |
mov [cache_ide0_search_start-cache_ide0+eax], edi |
pop eax |
ret |
.bd_appl_data: |
mov [cache_ide0_appl_search_start-cache_ide0+eax], edi |
pop eax |
ret |
;-------------------------------------------------------------------- |
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: |
pusha |
.ide0: |
xor eax, eax |
cmp [cdpos], 1 |
jne .ide1 |
mov [cache_ide0_search_start], eax |
mov ecx, [cache_ide0_system_sad_size] |
mov edi, [cache_ide0_pointer] |
call .clear |
mov [cache_ide0_appl_search_start], eax |
mov ecx, [cache_ide0_appl_sad_size] |
mov edi, [cache_ide0_data_pointer] |
jmp .continue |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
mov [cache_ide1_search_start], eax |
mov ecx, [cache_ide1_system_sad_size] |
mov edi, [cache_ide1_pointer] |
call .clear |
mov [cache_ide1_appl_search_start], eax |
mov ecx, [cache_ide1_appl_sad_size] |
mov edi, [cache_ide1_data_pointer] |
jmp .continue |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
mov [cache_ide2_search_start], eax |
mov ecx, [cache_ide2_system_sad_size] |
mov edi, [cache_ide2_pointer] |
call .clear |
mov [cache_ide2_appl_search_start], eax |
mov ecx, [cache_ide2_appl_sad_size] |
mov edi, [cache_ide2_data_pointer] |
jmp .continue |
.ide3: |
mov [cache_ide3_search_start], eax |
mov ecx, [cache_ide3_system_sad_size] |
mov edi, [cache_ide3_pointer] |
call .clear |
mov [cache_ide3_appl_search_start], eax |
mov ecx, [cache_ide3_appl_sad_size] |
mov edi, [cache_ide3_data_pointer] |
.continue: |
call .clear |
popa |
ret |
.clear: |
shl ecx, 1 |
cld |
rep stosd |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache: |
; mov ecx,cache_max ; entries in cache |
; mov esi,HD_CACHE+8 |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov ecx, [cache_ide0_system_sad_size] |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov ecx, [cache_ide0_appl_sad_size] |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov ecx, [cache_ide1_system_sad_size] |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov ecx, [cache_ide1_appl_sad_size] |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov ecx, [cache_ide2_system_sad_size] |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov ecx, [cache_ide2_appl_sad_size] |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov ecx, [cache_ide3_system_sad_size] |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov ecx, [cache_ide3_appl_sad_size] |
mov esi, [cache_ide3_data_pointer] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_1: |
; lea esi,[edi*8+HD_CACHE] |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov esi, [cache_ide0_pointer] |
ret |
.ide0_appl_data: |
mov esi, [cache_ide0_data_pointer] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov esi, [cache_ide1_pointer] |
ret |
.ide1_appl_data: |
mov esi, [cache_ide1_data_pointer] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov esi, [cache_ide2_pointer] |
ret |
.ide2_appl_data: |
mov esi, [cache_ide2_data_pointer] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov esi, [cache_ide3_pointer] |
ret |
.ide3_appl_data: |
mov esi, [cache_ide3_data_pointer] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_2: |
; add esi,HD_CACHE+65536 |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov eax, [cache_ide0_system_data] |
ret |
.ide0_appl_data: |
mov eax, [cache_ide0_appl_data] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov eax, [cache_ide1_system_data] |
ret |
.ide1_appl_data: |
mov eax, [cache_ide1_appl_data] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov eax, [cache_ide2_system_data] |
ret |
.ide2_appl_data: |
mov eax, [cache_ide2_appl_data] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov eax, [cache_ide3_system_data] |
ret |
.ide3_appl_data: |
mov eax, [cache_ide3_appl_data] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_3: |
; mov ecx,cache_max*10/100 |
; mov edi,[cache_search_start] |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov edi, [cache_ide0_search_start] |
ret |
.ide0_appl_data: |
mov edi, [cache_ide0_appl_search_start] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov edi, [cache_ide1_search_start] |
ret |
.ide1_appl_data: |
mov edi, [cache_ide1_appl_search_start] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov edi, [cache_ide2_search_start] |
ret |
.ide2_appl_data: |
mov edi, [cache_ide2_appl_search_start] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov edi, [cache_ide3_search_start] |
ret |
.ide3_appl_data: |
mov edi, [cache_ide3_appl_search_start] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_4: |
; cmp edi,cache_max |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
cmp edi, [cache_ide0_system_sad_size] |
ret |
.ide0_appl_data: |
cmp edi, [cache_ide0_appl_sad_size] |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
cmp edi, [cache_ide1_system_sad_size] |
ret |
.ide1_appl_data: |
cmp edi, [cache_ide1_appl_sad_size] |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
cmp edi, [cache_ide2_system_sad_size] |
ret |
.ide2_appl_data: |
cmp edi, [cache_ide2_appl_sad_size] |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
cmp edi, [cache_ide3_system_sad_size] |
ret |
.ide3_appl_data: |
cmp edi, [cache_ide3_appl_sad_size] |
ret |
;-------------------------------------------------------------------- |
align 4 |
cd_calculate_cache_5: |
; mov [cache_search_start],edi |
; 1 - IDE0 ... 4 - IDE3 |
.ide0: |
cmp [cdpos], 1 |
jne .ide1 |
cmp [cd_appl_data], 0 |
jne .ide0_appl_data |
mov [cache_ide0_search_start], edi |
ret |
.ide0_appl_data: |
mov [cache_ide0_appl_search_start], edi |
ret |
.ide1: |
cmp [cdpos], 2 |
jne .ide2 |
cmp [cd_appl_data], 0 |
jne .ide1_appl_data |
mov [cache_ide1_search_start], edi |
ret |
.ide1_appl_data: |
mov [cache_ide1_appl_search_start], edi |
ret |
.ide2: |
cmp [cdpos], 3 |
jne .ide3 |
cmp [cd_appl_data], 0 |
jne .ide2_appl_data |
mov [cache_ide2_search_start], edi |
ret |
.ide2_appl_data: |
mov [cache_ide2_appl_search_start], edi |
ret |
.ide3: |
cmp [cd_appl_data], 0 |
jne .ide3_appl_data |
mov [cache_ide3_search_start], edi |
ret |
.ide3_appl_data: |
mov [cache_ide3_appl_search_start], edi |
ret |
;-------------------------------------------------------------------- |
;align 4 |
;calculate_linear_to_real: |
; shr eax, 12 |
; mov eax, [page_tabs+eax*4] |
; and eax, 0xFFFFF000 |
; ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/rdsave.inc |
---|
0,0 → 1,30 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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) |
dd 1440*1024 ; size 1440 Kb |
dd RAMDISK |
db 0 |
.name: |
dd ? |
endg |
sysfn_saveramdisk: ; 18.6 = SAVE FLOPPY IMAGE (HD version only) |
call restorefatchain |
mov ebx, saverd_fileinfo |
mov [saverd_fileinfo.name], ecx |
pushad |
call file_system_lfn_protected ;in ebx |
popad |
mov [esp+32], eax |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/cd_drv.inc |
---|
0,0 → 1,931 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;********************************************************** |
; Íåïîñðåäñòâåííàÿ ðàáîòà ñ óñòðîéñòâîì ÑD (ATAPI) |
;********************************************************** |
; Àâòîð ÷àñòè èñõîäíîãî òåêñòà Êóëàêîâ Âëàäèìèð Ãåííàäüåâè÷ |
; Àäàïòàöèÿ, äîðàáîòêà è ðàçðàáîòêà Mario79,<Lrz> |
; Ìàêñèìàëüíîå êîëè÷åñòâî ïîâòîðåíèé îïåðàöèè ÷òåíèÿ |
MaxRetr equ 10 |
; Ïðåäåëüíîå âðåìÿ îæèäàíèÿ ãîòîâíîñòè ê ïðèåìó êîìàíäû |
; (â òèêàõ) |
BSYWaitTime equ 1000 ;2 |
NoTickWaitTime equ 0xfffff |
CDBlockSize equ 2048 |
;******************************************** |
;* ×ÒÅÍÈÅ ÑÅÊÒÎÐÀ Ñ ÏÎÂÒÎÐÀÌÈ * |
;* Ìíîãîêðàòíîå ïîâòîðåíèå ÷òåíèÿ ïðè ñáîÿõ * |
;******************************************** |
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 |
.hdreadcache: |
; cmp dword [esi+4],0 ; empty |
; je .nohdcache |
cmp [esi], eax ; correct sector |
je .yeshdcache |
.nohdcache: |
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 |
; mov dword [esi+4],1 ; hd read - mark as same as in hd |
.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 |
; Öèêë, ïîêà êîìàíäà íå âûïîëíåíà óñïåøíî èëè íå |
; èñ÷åðïàíî êîëè÷åñòâî ïîïûòîê |
mov ECX, MaxRetr |
@@NextRetr: |
; Ïîäàòü êîìàíäó |
;************************************************* |
;* ÏÎËÍÎÅ ×ÒÅÍÈÅ ÑÅÊÒÎÐÀ ÊÎÌÏÀÊÒ-ÄÈÑÊÀ * |
;* Ñ÷èòûâàþòñÿ äàííûå ïîëüçîâàòåëÿ, èíôîðìàöèÿ * |
;* ñóáêàíàëà è êîíòðîëüíàÿ èíôîðìàöèÿ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå; * |
;* CDSectorAddress - àäðåñ ñ÷èòûâàåìîãî ñåêòîðà. * |
;* Äàííûå ñ÷èòûâàåòñÿ â ìàññèâ CDDataBuf. * |
;************************************************* |
;ReadCD: |
push ecx |
; pusha |
; Çàäàòü ðàçìåð ñåêòîðà |
; mov [CDBlockSize],2048 ;2352 |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Ñôîðìèðîâàòü ïàêåòíóþ êîìàíäó äëÿ ñ÷èòûâàíèÿ |
; ñåêòîðà äàííûõ |
; Çàäàòü êîä êîìàíäû Read CD |
mov [PacketCommand], byte 0x28;0xBE |
; Çàäàòü àäðåñ ñåêòîðà |
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 |
; mov eax,[CDSectorAddress] |
; mov [PacketCommand+2],eax |
; Çàäàòü êîëè÷åñòâî ñ÷èòûâàåìûõ ñåêòîðîâ |
mov [PacketCommand+8], byte 1 |
; Çàäàòü ñ÷èòûâàíèå äàííûõ â ïîëíîì îáúåìå |
; mov [PacketCommand+9],byte 0xF8 |
; Ïîäàòü êîìàíäó |
call SendPacketDatCommand |
pop ecx |
; ret |
; cmp [DevErrorCode],0 |
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 |
.wait: |
dec eax |
; test eax,eax |
jz @@NextRetr |
jmp .wait |
@@: |
; Çàäåðæêà íà 2,5 ñåêóíäû |
; mov EAX,[timer_ticks] |
; add EAX,50 ;250 |
;@@Wait: |
; call change_task |
; cmp EAX,[timer_ticks] |
; ja @@Wait |
loop @@NextRetr |
@@End_4: |
mov dword [DevErrorCode], eax |
popad |
ret |
; Óíèâåðñàëüíûå ïðîöåäóðû, îáåñïå÷èâàþùèå âûïîëíåíèå |
; ïàêåòíûõ êîìàíä â ðåæèìå PIO |
; Ìàêñèìàëüíî äîïóñòèìîå âðåìÿ îæèäàíèÿ ðåàêöèè |
; óñòðîéñòâà íà ïàêåòíóþ êîìàíäó (â òèêàõ) |
MaxCDWaitTime equ 1000 ;200 ;10 ñåêóíä |
uglobal |
; Îáëàñòü ïàìÿòè äëÿ ôîðìèðîâàíèÿ ïàêåòíîé êîìàíäû |
PacketCommand: |
rb 12 ;DB 12 DUP (?) |
; Îáëàñòü ïàìÿòè äëÿ ïðèåìà äàííûõ îò äèñêîâîäà |
;CDDataBuf DB 4096 DUP (0) |
; Ðàçìåð ïðèíèìàåìîãî áëîêà äàííûõ â áàéòàõ |
;CDBlockSize DW ? |
; Àäðåñ ñ÷èòûâàåìîãî ñåêòîðà äàííûõ |
CDSectorAddress: |
DD ? |
; Âðåìÿ íà÷àëà î÷åðåäíîé îïåðàöèè ñ äèñêîì |
TickCounter_1 DD 0 |
; Âðåìÿ íà÷àëà îæèäàíèÿ ãîòîâíîñòè óñòðîéñòâà |
WURStartTime DD 0 |
; óêàçàòåëü áóôåðà äëÿ ñ÷èòûâàíèÿ |
CDDataBuf_pointer dd 0 |
endg |
;**************************************************** |
;* ÏÎÑËÀÒÜ ÓÑÒÐÎÉÑÒÂÓ ATAPI ÏÀÊÅÒÍÓÞ ÊÎÌÀÍÄÓ, * |
;* ÏÐÅÄÓÑÌÀÒÐÈÂÀÞÙÓÞ ÏÅÐÅÄÀ×Ó ÎÄÍÎÃÎ ÑÅÊÒÎÐÀ ÄÀÍÍÛÕ * |
;* ÐÀÇÌÅÐÎÌ 2048 ÁÀÉÒ ÎÒ ÓÑÒÐÎÉÑÒÂÀ Ê ÕÎÑÒÓ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå; * |
;* PacketCommand - 12-áàéòíûé êîìàíäíûé ïàêåò; * |
;* CDBlockSize - ðàçìåð ïðèíèìàåìîãî áëîêà äàííûõ. * |
; return eax DevErrorCode |
;**************************************************** |
SendPacketDatCommand: |
xor eax, eax |
; mov byte [DevErrorCode],al |
; Çàäàòü ðåæèì CHS |
mov byte [ATAAddressMode], al |
; Ïîñëàòü ATA-êîìàíäó ïåðåäà÷è ïàêåòíîé êîìàíäû |
mov byte [ATAFeatures], al |
mov byte [ATASectorCount], al |
mov byte [ATASectorNumber], al |
; Çàãðóçèòü ðàçìåð ïåðåäàâàåìîãî áëîêà |
mov [ATAHead], al |
; mov AX,[CDBlockSize] |
mov [ATACylinder], CDBlockSize |
mov [ATACommand], 0A0h |
call SendCommandToHDD_1 |
test eax, eax |
; cmp [DevErrorCode],0 ;ïðîâåðèòü êîä îøèáêè |
jnz @@End_8 ;çàêîí÷èòü, ñîõðàíèâ êîä îøèáêè |
; Îæèäàíèå ãîòîâíîñòè äèñêîâîäà ê ïðèåìó |
; ïàêåòíîé êîìàíäû |
mov DX, [ATABasePortAddr] |
add DX, 7 ;ïîðò 1õ7h |
mov ecx, NoTickWaitTime |
@@WaitDevice0: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_1 |
jmp .test |
@@: |
call change_task |
; Ïðîâåðèòü âðåìÿ âûïîëíåíèÿ êîìàíäû |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, BSYWaitTime |
ja @@Err1_1 ;îøèáêà òàéì-àóòà |
; Ïðîâåðèòü ãîòîâíîñòü |
.test: |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitDevice0 |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Err6 |
test AL, 08h ;ñîñòîÿíèå ñèãíàëà DRQ |
jz @@WaitDevice0 |
; Ïîñëàòü ïàêåòíóþ êîìàíäó |
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 |
; Îæèäàíèå ãîòîâíîñòè äàííûõ |
mov DX, [ATABasePortAddr] |
add DX, 7 ;ïîðò 1õ7h |
mov ecx, NoTickWaitTime |
@@WaitDevice1: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_1 |
jmp .test_1 |
@@: |
call change_task |
; Ïðîâåðèòü âðåìÿ âûïîëíåíèÿ êîìàíäû |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, MaxCDWaitTime |
ja @@Err1_1 ;îøèáêà òàéì-àóòà |
; Ïðîâåðèòü ãîòîâíîñòü |
.test_1: |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitDevice1 |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Err6_temp |
test AL, 08h ;ñîñòîÿíèå ñèãíàëà DRQ |
jz @@WaitDevice1 |
; Ïðèíÿòü áëîê äàííûõ îò êîíòðîëëåðà |
mov EDI, [CDDataBuf_pointer];0x7000 ;CDDataBuf |
; Çàãðóçèòü àäðåñ ðåãèñòðà äàííûõ êîíòðîëëåðà |
mov DX, [ATABasePortAddr];ïîðò 1x0h |
; Çàãðóçèòü â ñ÷åò÷èê ðàçìåð áëîêà â áàéòàõ |
xor ecx, ecx |
mov CX, CDBlockSize |
; Âû÷èñëèòü ðàçìåð áëîêà â 16-ðàçðÿäíûõ ñëîâàõ |
shr CX, 1;ðàçäåëèòü ðàçìåð áëîêà íà 2 |
; Ïðèíÿòü áëîê äàííûõ |
cli |
cld |
rep insw |
sti |
; Óñïåøíîå çàâåðøåíèå ïðèåìà äàííûõ |
@@End_8: |
xor eax, eax |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Err1_1: |
xor eax, eax |
inc eax |
ret |
; mov [DevErrorCode],1 |
; ret |
@@Err6_temp: |
mov eax, 7 |
ret |
; mov [DevErrorCode],7 |
; ret |
@@Err6: |
mov eax, 6 |
ret |
; mov [DevErrorCode],6 |
;@@End_8: |
; ret |
;*********************************************** |
;* ÏÎÑËÀÒÜ ÓÑÒÐÎÉÑÒÂÓ ATAPI ÏÀÊÅÒÍÓÞ ÊÎÌÀÍÄÓ, * |
;* ÍÅ ÏÐÅÄÓÑÌÀÒÐÈÂÀÞÙÓÞ ÏÅÐÅÄÀ×È ÄÀÍÍÛÕ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç * |
;* ãëîáàëüíûå ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå; * |
;* PacketCommand - 12-áàéòíûé êîìàíäíûé ïàêåò. * |
;*********************************************** |
SendPacketNoDatCommand: |
pushad |
xor eax, eax |
; mov byte [DevErrorCode],al |
; Çàäàòü ðåæèì CHS |
mov byte [ATAAddressMode], al |
; Ïîñëàòü ATA-êîìàíäó ïåðåäà÷è ïàêåòíîé êîìàíäû |
mov byte [ATAFeatures], al |
mov byte [ATASectorCount], al |
mov byte [ATASectorNumber], al |
mov word [ATACylinder], ax |
mov byte [ATAHead], al |
mov [ATACommand], 0A0h |
call SendCommandToHDD_1 |
; cmp [DevErrorCode],0 ;ïðîâåðèòü êîä îøèáêè |
test eax, eax |
jnz @@End_9 ;çàêîí÷èòü, ñîõðàíèâ êîä îøèáêè |
; Îæèäàíèå ãîòîâíîñòè äèñêîâîäà ê ïðèåìó |
; ïàêåòíîé êîìàíäû |
mov DX, [ATABasePortAddr] |
add DX, 7 ;ïîðò 1õ7h |
@@WaitDevice0_1: |
call change_task |
; Ïðîâåðèòü âðåìÿ îæèäàíèÿ |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, BSYWaitTime |
ja @@Err1_3 ;îøèáêà òàéì-àóòà |
; Ïðîâåðèòü ãîòîâíîñòü |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitDevice0_1 |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Err6_1 |
test AL, 08h ;ñîñòîÿíèå ñèãíàëà DRQ |
jz @@WaitDevice0_1 |
; Ïîñëàòü ïàêåòíóþ êîìàíäó |
; 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 |
; Îæèäàíèå ïîäòâåðæäåíèÿ ïðèåìà êîìàíäû |
mov DX, [ATABasePortAddr] |
add DX, 7 ;ïîðò 1õ7h |
@@WaitDevice1_1: |
call change_task |
; Ïðîâåðèòü âðåìÿ âûïîëíåíèÿ êîìàíäû |
mov EAX, [timer_ticks] |
sub EAX, [TickCounter_1] |
cmp EAX, MaxCDWaitTime |
ja @@Err1_3 ;îøèáêà òàéì-àóòà |
; Îæèäàòü îñâîáîæäåíèÿ óñòðîéñòâà |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitDevice1_1 |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Err6_1 |
test AL, 40h ;ñîñòîÿíèå ñèãíàëà DRDY |
jz @@WaitDevice1_1 |
@@clear_DEC: |
and [DevErrorCode], 0 |
popad |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Err1_3: |
xor eax, eax |
inc eax |
jmp @@End_9 |
@@Err6_1: |
mov eax, 6 |
@@End_9: |
mov [DevErrorCode], eax |
popad |
ret |
;**************************************************** |
;* ÏÎÑËÀÒÜ ÊÎÌÀÍÄÓ ÇÀÄÀÍÍÎÌÓ ÄÈÑÊÓ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà (1 èëè 2); * |
;* DiskNumber - íîìåð äèñêà (0 èëè 1); * |
;* ATAFeatures - "îñîáåííîñòè"; * |
;* ATASectorCount - êîëè÷åñòâî ñåêòîðîâ; * |
;* ATASectorNumber - íîìåð íà÷àëüíîãî ñåêòîðà; * |
;* ATACylinder - íîìåð íà÷àëüíîãî öèëèíäðà; * |
;* ATAHead - íîìåð íà÷àëüíîé ãîëîâêè; * |
;* ATAAddressMode - ðåæèì àäðåñàöèè (0-CHS, 1-LBA); * |
;* ATACommand - êîä êîìàíäû. * |
;* Ïîñëå óñïåøíîãî âûïîëíåíèÿ ôóíêöèè: * |
;* â ATABasePortAddr - áàçîâûé àäðåñ HDD; * |
;* â DevErrorCode - íîëü. * |
;* Ïðè âîçíèêíîâåíèè îøèáêè â DevErrorCode áóäåò * |
;* âîçâðàùåí êîä îøèáêè â eax * |
;**************************************************** |
SendCommandToHDD_1: |
; pushad |
; mov [DevErrorCode],0 not need |
; Ïðîâåðèòü çíà÷åíèå êîäà ðåæèìà |
cmp [ATAAddressMode], 1 |
ja @@Err2_4 |
; Ïðîâåðèòü êîððåêòíîñòü íîìåðà êàíàëà |
mov BX, [ChannelNumber] |
cmp BX, 1 |
jb @@Err3_4 |
cmp BX, 2 |
ja @@Err3_4 |
; Óñòàíîâèòü áàçîâûé àäðåñ |
dec BX |
shl BX, 1 |
movzx ebx, bx |
mov AX, [ebx+StandardATABases] |
mov [ATABasePortAddr], AX |
; Îæèäàíèå ãîòîâíîñòè HDD ê ïðèåìó êîìàíäû |
; Âûáðàòü íóæíûé äèñê |
mov DX, [ATABasePortAddr] |
add DX, 6 ;àäðåñ ðåãèñòðà ãîëîâîê |
mov AL, [DiskNumber] |
cmp AL, 1 ;ïðîâåðèòü íîìåðà äèñêà |
ja @@Err4_4 |
shl AL, 4 |
or AL, 10100000b |
out DX, AL |
; Îæèäàòü, ïîêà äèñê íå áóäåò ãîòîâ |
inc DX |
mov eax, [timer_ticks] |
mov [TickCounter_1], eax |
mov ecx, NoTickWaitTime |
@@WaitHDReady_2: |
cmp [timer_ticks_enable], 0 |
jne @f |
dec ecx |
; test ecx,ecx |
jz @@Err1_4 |
jmp .test |
@@: |
call change_task |
; Ïðîâåðèòü âðåìÿ îæèäàíèÿ |
mov eax, [timer_ticks] |
sub eax, [TickCounter_1] |
cmp eax, BSYWaitTime;300 ;îæèäàòü 3 ñåê. |
ja @@Err1_4 ;îøèáêà òàéì-àóòà |
; Ïðî÷èòàòü ðåãèñòð ñîñòîÿíèÿ |
.test: |
in AL, DX |
; Ïðîâåðèòü ñîñòîÿíèå ñèãíàëà BSY |
test AL, 80h |
jnz @@WaitHDReady_2 |
; Ïðîâåðèòü ñîñòîÿíèå ñèãíàëà DRQ |
test AL, 08h |
jnz @@WaitHDReady_2 |
; Çàãðóçèòü êîìàíäó â ðåãèñòðû êîíòðîëëåðà |
cli |
mov DX, [ATABasePortAddr] |
inc DX ;ðåãèñòð "îñîáåííîñòåé" |
mov AL, [ATAFeatures] |
out DX, AL |
inc DX ;ñ÷åò÷èê ñåêòîðîâ |
mov AL, [ATASectorCount] |
out DX, AL |
inc DX ;ðåãèñòð íîìåðà ñåêòîðà |
mov AL, [ATASectorNumber] |
out DX, AL |
inc DX ;íîìåð öèëèíäðà (ìëàäøèé áàéò) |
mov AX, [ATACylinder] |
out DX, AL |
inc DX ;íîìåð öèëèíäðà (ñòàðøèé áàéò) |
mov AL, AH |
out DX, AL |
inc DX ;íîìåð ãîëîâêè/íîìåð äèñêà |
mov AL, [DiskNumber] |
shl AL, 4 |
cmp [ATAHead], 0Fh;ïðîâåðèòü íîìåð ãîëîâêè |
ja @@Err5_4 |
or AL, [ATAHead] |
or AL, 10100000b |
mov AH, [ATAAddressMode] |
shl AH, 6 |
or AL, AH |
out DX, AL |
; Ïîñëàòü êîìàíäó |
mov AL, [ATACommand] |
inc DX ;ðåãèñòð êîìàíä |
out DX, AL |
sti |
; Ñáðîñèòü ïðèçíàê îøèáêè |
; mov [DevErrorCode],0 |
@@End_10: |
xor eax, eax |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Err1_4: |
xor eax, eax |
inc eax |
; mov [DevErrorCode],1 |
ret |
@@Err2_4: |
mov eax, 2 |
; mov [DevErrorCode],2 |
ret |
@@Err3_4: |
mov eax, 3 |
; mov [DevErrorCode],3 |
ret |
@@Err4_4: |
mov eax, 4 |
; mov [DevErrorCode],4 |
ret |
@@Err5_4: |
mov eax, 5 |
; mov [DevErrorCode],5 |
; Çàâåðøåíèå ðàáîòû ïðîãðàììû |
ret |
; sti |
; popad |
;************************************************* |
;* ÎÆÈÄÀÍÈÅ ÃÎÒÎÂÍÎÑÒÈ ÓÑÒÐÎÉÑÒÂÀ Ê ÐÀÁÎÒÅ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
WaitUnitReady: |
pusha |
; Çàïîìíèòü âðåìÿ íà÷àëà îïåðàöèè |
mov EAX, [timer_ticks] |
mov [WURStartTime], EAX |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Ñôîðìèðîâàòü êîìàíäó TEST UNIT READY |
mov [PacketCommand], word 00h |
; ÖÈÊË ÎÆÈÄÀÍÈß ÃÎÒÎÂÍÎÑÒÈ ÓÑÒÐÎÉÑÒÂÀ |
mov ecx, NoTickWaitTime |
@@SendCommand: |
; Ïîäàòü êîìàíäó ïðîâåðêè ãîòîâíîñòè |
call SendPacketNoDatCommand |
cmp [timer_ticks_enable], 0 |
jne @f |
cmp [DevErrorCode], 0 |
je @@End_11 |
dec ecx |
; cmp ecx,0 |
jz .Error |
jmp @@SendCommand |
@@: |
call change_task |
; Ïðîâåðèòü êîä îøèáêè |
cmp [DevErrorCode], 0 |
je @@End_11 |
; Ïðîâåðèòü âðåìÿ îæèäàíèÿ ãîòîâíîñòè |
mov EAX, [timer_ticks] |
sub EAX, [WURStartTime] |
cmp EAX, MaxCDWaitTime |
jb @@SendCommand |
.Error: |
; Îøèáêà òàéì-àóòà |
mov [DevErrorCode], 1 |
@@End_11: |
popa |
ret |
;************************************************* |
;* ÇÀÏÐÅÒÈÒÜ ÑÌÅÍÓ ÄÈÑÊÀ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
prevent_medium_removal: |
pusha |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Çàäàòü êîä êîìàíäû |
mov [PacketCommand], byte 0x1E |
; Çàäàòü êîä çàïðåòà |
mov [PacketCommand+4], byte 11b |
; Ïîäàòü êîìàíäó |
call SendPacketNoDatCommand |
mov eax, ATAPI_IDE0_lock |
add eax, [cdpos] |
dec eax |
mov [eax], byte 1 |
popa |
ret |
;************************************************* |
;* ÐÀÇÐÅØÈÒÜ ÑÌÅÍÓ ÄÈÑÊÀ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
allow_medium_removal: |
pusha |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Çàäàòü êîä êîìàíäû |
mov [PacketCommand], byte 0x1E |
; Çàäàòü êîä çàïðåòà |
mov [PacketCommand+4], byte 00b |
; Ïîäàòü êîìàíäó |
call SendPacketNoDatCommand |
mov eax, ATAPI_IDE0_lock |
add eax, [cdpos] |
dec eax |
mov [eax], byte 0 |
popa |
ret |
;************************************************* |
;* ÇÀÃÐÓÇÈÒÜ ÍÎÑÈÒÅËÜ Â ÄÈÑÊÎÂÎÄ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
LoadMedium: |
pusha |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Ñôîðìèðîâàòü êîìàíäó START/STOP UNIT |
; Çàäàòü êîä êîìàíäû |
mov [PacketCommand], word 1Bh |
; Çàäàòü îïåðàöèþ çàãðóçêè íîñèòåëÿ |
mov [PacketCommand+4], word 00000011b |
; Ïîäàòü êîìàíäó |
call SendPacketNoDatCommand |
popa |
ret |
;************************************************* |
;* ÈÇÂËÅ×Ü ÍÎÑÈÒÅËÜ ÈÇ ÄÈÑÊÎÂÎÄÀ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
EjectMedium: |
pusha |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Ñôîðìèðîâàòü êîìàíäó START/STOP UNIT |
; Çàäàòü êîä êîìàíäû |
mov [PacketCommand], word 1Bh |
; Çàäàòü îïåðàöèþ èçâëå÷åíèÿ íîñèòåëÿ |
mov [PacketCommand+4], word 00000010b |
; Ïîäàòü êîìàíäó |
call SendPacketNoDatCommand |
popa |
ret |
;************************************************* |
;* Ïðîâåðèòü ñîáûòèå íàæàòèÿ êíîïêè èçâëå÷åíèÿ * |
;* äèñêà * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
align 4 |
check_ATAPI_device_event: |
pusha |
mov eax, [timer_ticks] |
sub eax, [timer_ATAPI_check] |
cmp eax, 100 |
jb .end_1 |
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 |
.end: |
sti |
mov eax, [timer_ticks] |
mov [timer_ATAPI_check], eax |
.end_1: |
popa |
ret |
.ide3: |
cli |
cmp [ATAPI_IDE3_lock], 1 |
jne .ide2_1 |
cmp [IDE_Channel_2], 0 |
jne .ide1_1 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 1 |
mov [cdpos], 4 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide3 |
call syscall_cdaudio.free |
jmp .ide2_1 |
.eject_ide3: |
call .eject |
call syscall_cdaudio.free |
jmp .ide2_1 |
.ide2: |
cli |
cmp [ATAPI_IDE2_lock], 1 |
jne .ide1_1 |
cmp [IDE_Channel_2], 0 |
jne .ide1_1 |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_2], 1 |
call reserve_ok2 |
mov [ChannelNumber], 2 |
mov [DiskNumber], 0 |
mov [cdpos], 3 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide2 |
call syscall_cdaudio.free |
jmp .ide1_1 |
.eject_ide2: |
call .eject |
call syscall_cdaudio.free |
jmp .ide1_1 |
.ide1: |
cli |
cmp [ATAPI_IDE1_lock], 1 |
jne .ide0_1 |
cmp [IDE_Channel_1], 0 |
jne .end |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 1 |
mov [cdpos], 2 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide1 |
call syscall_cdaudio.free |
jmp .ide0_1 |
.eject_ide1: |
call .eject |
call syscall_cdaudio.free |
jmp .ide0_1 |
.ide0: |
cli |
cmp [ATAPI_IDE0_lock], 1 |
jne .end |
cmp [IDE_Channel_1], 0 |
jne .end |
cmp [cd_status], 0 |
jne .end |
mov [IDE_Channel_1], 1 |
call reserve_ok2 |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
mov [cdpos], 1 |
call GetEvent_StatusNotification |
cmp [CDDataBuf+4], byte 1 |
je .eject_ide0 |
call syscall_cdaudio.free |
jmp .end |
.eject_ide0: |
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 |
ignore_CD_eject_wait db 0 |
endg |
;************************************************* |
;* Ïîëó÷èòü ñîîáùåíèå î ñîáûòèè èëè ñîñòîÿíèè * |
;* óñòðîéñòâà * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
GetEvent_StatusNotification: |
pusha |
mov [CDDataBuf_pointer], CDDataBuf |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Çàäàòü êîä êîìàíäû |
mov [PacketCommand], byte 4Ah |
mov [PacketCommand+1], byte 00000001b |
; Çàäàòü çàïðîñ êëàññà ñîîáùåíèé |
mov [PacketCommand+4], byte 00010000b |
; Ðàçìåð âûäåëåííîé îáëàñòè |
mov [PacketCommand+7], byte 8h |
mov [PacketCommand+8], byte 0h |
; Ïîäàòü êîìàíäó |
call SendPacketDatCommand |
popa |
ret |
;************************************************* |
; ïðî÷èòàòü èíôîðìàöèþ èç TOC |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
Read_TOC: |
pusha |
mov [CDDataBuf_pointer], CDDataBuf |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
call clear_packet_buffer |
; Ñôîðìèðîâàòü ïàêåòíóþ êîìàíäó äëÿ ñ÷èòûâàíèÿ |
; ñåêòîðà äàííûõ |
mov [PacketCommand], byte 0x43 |
; Çàäàòü ôîðìàò |
mov [PacketCommand+2], byte 1 |
; Ðàçìåð âûäåëåííîé îáëàñòè |
mov [PacketCommand+7], byte 0xFF |
mov [PacketCommand+8], byte 0h |
; Ïîäàòü êîìàíäó |
call SendPacketDatCommand |
popa |
ret |
;************************************************* |
;* ÎÏÐÅÄÅËÈÒÜ ÎÁÙÅÅ ÊÎËÈ×ÅÑÒÂÎ ÑÅÊÒÎÐΠÍÀ ÄÈÑÊÅ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;************************************************* |
;ReadCapacity: |
; pusha |
;; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
; call clear_packet_buffer |
;; Çàäàòü ðàçìåð áóôåðà â áàéòàõ |
; mov [CDBlockSize],8 |
;; Ñôîðìèðîâàòü êîìàíäó READ CAPACITY |
; mov [PacketCommand],word 25h |
;; Ïîäàòü êîìàíäó |
; call SendPacketDatCommand |
; popa |
; ret |
clear_packet_buffer: |
; Î÷èñòèòü áóôåð ïàêåòíîé êîìàíäû |
and [PacketCommand], dword 0 |
and [PacketCommand+4], dword 0 |
and [PacketCommand+8], dword 0 |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/cdrom.inc |
---|
0,0 → 1,271 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
sys_cd_audio: |
cmp word [cdbase], word 0 |
jnz @f |
mov eax, 1 |
ret |
@@: |
; eax=1 cdplay at ebx 0x00FFSSMM |
; eax=2 get tracklist size of ecx to [ebx] |
; eax=3 stop/pause playing |
cmp eax, 1 |
jnz nocdp |
call sys_cdplay |
ret |
nocdp: |
cmp eax, 2 |
jnz nocdtl |
mov edi, [TASK_BASE] |
add edi, TASKDATA.mem_start |
add ebx, [edi] |
call sys_cdtracklist |
ret |
nocdtl: |
cmp eax, 3 |
jnz nocdpause |
call sys_cdpause |
ret |
nocdpause: |
mov eax, 0xffffff01 |
ret |
sys_cd_atapi_command: |
pushad |
mov dx, word [cdbase] |
add dx, 6 |
mov ax, word [cdid] |
out dx, al |
mov esi, 10 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 7 |
in al, dx |
and al, 0x80 |
cmp al, 0 |
jnz res |
jmp cdl6 |
res: |
mov dx, word [cdbase] |
add dx, 7 |
mov al, 0x8 |
out dx, al |
mov dx, word [cdbase] |
add dx, 0x206 |
mov al, 0xe |
out dx, al |
mov esi, 1 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 0x206 |
mov al, 0x8 |
out dx, al |
mov esi, 30 |
call delay_ms |
xor cx, cx |
cdl5: |
inc cx |
cmp cx, 10 |
jz cdl6 |
mov dx, word [cdbase] |
add dx, 7 |
in al, dx |
and al, 0x88 |
cmp al, 0x00 |
jz cdl5 |
mov esi, 100 |
call delay_ms |
jmp cdl5 |
cdl6: |
mov dx, word [cdbase] |
add dx, 4 |
mov al, 0 |
out dx, al |
mov dx, word [cdbase] |
add dx, 5 |
mov al, 0 |
out dx, al |
mov dx, word [cdbase] |
add dx, 7 |
mov al, 0xec |
out dx, al |
mov esi, 5 |
call delay_ms |
mov dx, word [cdbase] |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 0 |
out dx, al |
add dx, 1 |
mov al, 128 |
out dx, al |
add dx, 2 |
mov al, 0xa0 |
out dx, al |
xor cx, cx |
mov dx, word [cdbase] |
add dx, 7 |
cdl1: |
inc cx |
cmp cx, 100 |
jz cdl2 |
in al, dx |
and ax, 0x88 |
cmp al, 0x8 |
jz cdl2 |
mov esi, 2 |
call delay_ms |
jmp cdl1 |
cdl2: |
popad |
ret |
sys_cdplay: |
mov ax, 5 |
push ax |
push ebx |
cdplay: |
call sys_cd_atapi_command |
cli |
mov dx, word [cdbase] |
mov ax, 0x0047 |
out dx, ax |
mov al, 1 |
mov ah, [esp+0]; min xx |
out dx, ax |
mov ax, [esp+1]; fr sec |
out dx, ax |
mov ax, 256+99 |
out dx, ax |
mov ax, 0x0001 |
out dx, ax |
mov ax, 0x0000 |
out dx, ax |
mov esi, 10 |
call delay_ms |
sti |
add dx, 7 |
in al, dx |
test al, 1 |
jz cdplayok |
mov ax, [esp+4] |
dec ax |
mov [esp+4], ax |
cmp ax, 0 |
jz cdplayfail |
jmp cdplay |
cdplayfail: |
cdplayok: |
pop ebx |
pop ax |
xor eax, eax |
ret |
sys_cdtracklist: |
push ebx |
tcdplay: |
call sys_cd_atapi_command |
mov dx, word [cdbase] |
mov ax, 0x43+2*256 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
mov ax, 200 |
out dx, ax |
mov ax, 0x0 |
out dx, ax |
in al, dx |
mov cx, 1000 |
mov dx, word [cdbase] |
add dx, 7 |
cld |
cdtrnwewait: |
mov esi, 10 |
call delay_ms |
in al, dx |
and al, 128 |
cmp al, 0 |
jz cdtrl1 |
loop cdtrnwewait |
cdtrl1: |
; read the result |
mov ecx, [esp+0] |
mov dx, word [cdbase] |
cdtrread: |
add dx, 7 |
in al, dx |
and al, 8 |
cmp al, 8 |
jnz cdtrdone |
sub dx, 7 |
in ax, dx |
mov [ecx], ax |
add ecx, 2 |
jmp cdtrread |
cdtrdone: |
pop ecx |
xor eax, eax |
ret |
sys_cdpause: |
call sys_cd_atapi_command |
mov dx, word [cdbase] |
mov ax, 0x004B |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov ax, 0 |
out dx, ax |
mov esi, 10 |
call delay_ms |
add dx, 7 |
in al, dx |
xor eax, eax |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/fdc.inc |
---|
0,0 → 1,71 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
iglobal |
;function pointers. |
fdc_irq_func dd fdc_null |
endg |
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 |
fdc_irq: |
call [fdc_irq_func] |
fdc_null: |
ret |
save_image: |
call reserve_flp |
call restorefatchain |
pusha |
call check_label |
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: |
push esi |
call take_data_from_application_1 |
pop esi |
add esi, 512 |
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: |
mov [fdc_irq_func], fdc_null |
popa |
mov [flp_status], 0 |
ret |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/flp_drv.inc |
---|
0,0 → 1,630 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;********************************************************** |
; Íåïîñðåäñòâåííàÿ ðàáîòà ñ êîíòðîëëåðîì ãèáêîãî äèñêà |
;********************************************************** |
; Àâòîð èñõîäíîãî òåêñòà Êóëàêîâ Âëàäèìèð Ãåííàäüåâè÷. |
; Àäàïòàöèÿ è äîðàáîòêà Mario79 |
;give_back_application_data: ; ïåðåñëàòü ïðèëîæåíèþ |
; 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 |
xor ecx, ecx |
mov cx, 128 |
cld |
rep movsd |
ret |
;take_data_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 |
xor ecx, ecx |
mov cx, 128 |
cld |
rep movsd |
ret |
; Êîäû çàâåðøåíèÿ îïåðàöèè ñ êîíòðîëëåðîì (FDC_Status) |
FDC_Normal equ 0 ;íîðìàëüíîå çàâåðøåíèå |
FDC_TimeOut equ 1 ;îøèáêà òàéì-àóòà |
FDC_DiskNotFound equ 2 ;â äèñêîâîäå íåò äèñêà |
FDC_TrackNotFound equ 3 ;äîðîæêà íå íàéäåíà |
FDC_SectorNotFound equ 4 ;ñåêòîð íå íàéäåí |
; Ìàêñèìàëüíûå çíà÷åíèÿ êîîðäèíàò ñåêòîðà (çàäàííûå |
; çíà÷åíèÿ ñîîòâåòñòâóþò ïàðàìåòðàì ñòàíäàðòíîãî |
; òðåõäþéìîâîãî ãèáêîãî äèñêà îáúåìîì 1,44 Ìá) |
MAX_Track equ 79 |
MAX_Head equ 1 |
MAX_Sector equ 18 |
uglobal |
; Ñ÷åò÷èê òèêîâ òàéìåðà |
TickCounter dd ? |
; Êîä çàâåðøåíèÿ îïåðàöèè ñ êîíòðîëëåðîì ÍÃÌÄ |
FDC_Status DB ? |
; Ôëàã ïðåðûâàíèÿ îò ÍÃÌÄ |
FDD_IntFlag DB ? |
; Ìîìåíò íà÷àëà ïîñëåäíåé îïåðàöèè ñ ÍÃÌÄ |
FDD_Time DD ? |
; Íîìåð äèñêîâîäà |
FDD_Type db 0 |
; Êîîðäèíàòû ñåêòîðà |
FDD_Track DB ? |
FDD_Head DB ? |
FDD_Sector DB ? |
; Áëîê ðåçóëüòàòà îïåðàöèè |
FDC_ST0 DB ? |
FDC_ST1 DB ? |
FDC_ST2 DB ? |
FDC_C DB ? |
FDC_H DB ? |
FDC_R DB ? |
FDC_N DB ? |
; Ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ÷òåíè |
ReadRepCounter DB ? |
; Ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ðåêàëèáðîâêè |
RecalRepCounter DB ? |
endg |
; Îáëàñòü ïàìÿòè äëÿ õðàíåíèÿ ïðî÷èòàííîãî ñåêòîðà |
;FDD_DataBuffer: times 512 db 0 ;DB 512 DUP (?) |
fdd_motor_status db 0 |
timer_fdd_motor dd 0 |
;************************************* |
;* ÈÍÈÖÈÀËÈÇÀÖÈß ÐÅÆÈÌÀ ÏÄÏ ÄËß ÍÃÌÄ * |
;************************************* |
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 |
;*********************************** |
;* ÇÀÏÈÑÀÒÜ ÁÀÉÒ Â ÏÎÐÒ ÄÀÍÍÛÕ FDC * |
;* Ïàðàìåòðû: * |
;* AL - âûâîäèìûé áàéò. * |
;*********************************** |
FDCDataOutput: |
; pusha |
push eax ecx edx |
mov AH, AL ;çàïîìíèòü áàéò â AH |
; Ñáðîñèòü ïåðåìåííóþ ñîñòîÿíèÿ êîíòðîëëåðà |
mov [FDC_Status], FDC_Normal |
; Ïðîâåðèòü ãîòîâíîñòü êîíòðîëëåðà ê ïðèåìó äàííûõ |
mov DX, 3F4h ;(ïîðò ñîñòîÿíèÿ FDC) |
mov ecx, 0x10000 ;óñòàíîâèòü ñ÷åò÷èê òàéì-àóòà |
@@TestRS: |
in AL, DX ;ïðî÷èòàòü ðåãèñòð RS |
and AL, 0C0h ;âûäåëèòü ðàçðÿäû 6 è 7 |
cmp AL, 80h ;ïðîâåðèòü ðàçðÿäû 6 è 7 |
je @@OutByteToFDC |
loop @@TestRS |
; Îøèáêà òàéì-àóòà |
mov [FDC_Status], FDC_TimeOut |
jmp @@End_5 |
; Âûâåñòè áàéò â ïîðò äàííûõ |
@@OutByteToFDC: |
inc DX |
mov AL, AH |
out DX, AL |
@@End_5: |
; popa |
pop edx ecx eax |
ret |
;****************************************** |
;* ÏÐÎ×ÈÒÀÒÜ ÁÀÉÒ ÈÇ ÏÎÐÒÀ ÄÀÍÍÛÕ FDC * |
;* Ïðîöåäóðà íå èìååò âõîäíûõ ïàðàìåòðîâ. * |
;* Âûõîäíûå äàííûå: * |
;* AL - ñ÷èòàííûé áàéò. * |
;****************************************** |
FDCDataInput: |
push ECX |
push DX |
; Ñáðîñèòü ïåðåìåííóþ ñîñòîÿíèÿ êîíòðîëëåðà |
mov [FDC_Status], FDC_Normal |
; Ïðîâåðèòü ãîòîâíîñòü êîíòðîëëåðà ê ïåðåäà÷å äàííûõ |
mov DX, 3F4h ;(ïîðò ñîñòîÿíèÿ FDC) |
xor CX, CX ;óñòàíîâèòü ñ÷åò÷èê òàéì-àóòà |
@@TestRS_1: |
in AL, DX ;ïðî÷èòàòü ðåãèñòð RS |
and AL, 0C0h ;âûäëèòü ðàçðÿäû 6 è 7 |
cmp AL, 0C0h ;ïðîâåðèòü ðàçðÿäû 6 è 7 |
je @@GetByteFromFDC |
loop @@TestRS_1 |
; Îøèáêà òàéì-àóòà |
mov [FDC_Status], FDC_TimeOut |
jmp @@End_6 |
; Ââåñòè áàéò èç ïîðòà äàííûõ |
@@GetByteFromFDC: |
inc DX |
in AL, DX |
@@End_6: |
pop DX |
pop ECX |
ret |
;********************************************* |
;* ÎÁÐÀÁÎÒ×ÈÊ ÏÐÅÐÛÂÀÍÈß ÎÒ ÊÎÍÒÐÎËËÅÐÀ ÍÃÌÄ * |
;********************************************* |
FDCInterrupt: |
; Óñòàíîâèòü ôëàã ïðåðûâàíè |
mov [FDD_IntFlag], 1 |
ret |
;****************************************** |
;* ÓÑÒÀÍÎÂÈÒÜ ÍÎÂÛÉ ÎÁÐÀÁÎÒ×ÈÊ ÏÐÅÐÛÂÀÍÈÉ * |
;* ÍÃÌÄ * |
;****************************************** |
SetUserInterrupts: |
mov [fdc_irq_func], FDCInterrupt |
ret |
;******************************************* |
;* ÎÆÈÄÀÍÈÅ ÏÐÅÐÛÂÀÍÈß ÎÒ ÊÎÍÒÐÎËËÅÐÀ ÍÃÌÄ * |
;******************************************* |
WaitFDCInterrupt: |
pusha |
; Ñáðîñèòü áàéò ñîñòîÿíèÿ îïåðàöèè |
mov [FDC_Status], FDC_Normal |
; Ñáðîñèòü ôëàã ïðåðûâàíè |
mov [FDD_IntFlag], 0 |
; Îáíóëèòü ñ÷åò÷èê òèêîâ |
mov eax, [timer_ticks] |
mov [TickCounter], eax |
; Îæèäàòü óñòàíîâêè ôëàãà ïðåðûâàíèÿ ÍÃÌÄ |
@@TestRS_2: |
cmp [FDD_IntFlag], 0 |
jnz @@End_7 ;ïðåðûâàíèå ïðîèçîøëî |
call change_task |
mov eax, [timer_ticks] |
sub eax, [TickCounter] |
cmp eax, 50 ;25 ;5 ;îæèäàòü 5 òèêîâ |
jb @@TestRS_2 |
; jl @@TestRS_2 |
; Îøèáêà òàéì-àóòà |
mov [FDC_Status], FDC_TimeOut |
; mov [flp_status],0 |
@@End_7: |
popa |
ret |
;********************************* |
;* ÂÊËÞ×ÈÒÜ ÌÎÒÎÐ ÄÈÑÊÎÂÎÄÀ "A:" * |
;********************************* |
FDDMotorON: |
pusha |
; cmp [fdd_motor_status],1 |
; je fdd_motor_on |
mov al, [flp_number] |
cmp [fdd_motor_status], al |
je fdd_motor_on |
; Ïðîèçâåñòè ñáðîñ êîíòðîëëåðà ÍÃÌÄ |
mov DX, 3F2h;ïîðò óïðàâëåíèÿ äâèãàòåëÿìè |
mov AL, 0 |
out DX, AL |
; Âûáðàòü è âêëþ÷èòü ìîòîð äèñêîâîäà |
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 |
; Îáíóëèòü ñ÷åò÷èê òèêîâ |
mov eax, [timer_ticks] |
mov [TickCounter], eax |
; Îæèäàòü 0,5 ñ |
@@dT: |
call change_task |
mov eax, [timer_ticks] |
sub eax, [TickCounter] |
cmp eax, 50 ;10 |
jb @@dT |
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 |
;***************************************** |
;* ÑÎÕÐÀÍÅÍÈÅ ÓÊÀÇÀÒÅËß ÂÐÅÌÅÍÈ * |
;***************************************** |
save_timer_fdd_motor: |
mov eax, [timer_ticks] |
mov [timer_fdd_motor], eax |
ret |
;***************************************** |
;* ÏÐÎÂÅÐÊÀ ÇÀÄÅÐÆÊÈ ÂÛÊËÞ×ÅÍÈß ÌÎÒÎÐÀ * |
;***************************************** |
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: |
mov [flp_status], 0 |
end_check_fdd_motor_status: |
ret |
;********************************** |
;* ÂÛÊËÞ×ÈÒÜ ÌÎÒÎÐ ÄÈÑÊÎÂÎÄÀ * |
;********************************** |
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 |
; ñáðîñ ôëàãîâ êåøèðîâàíèÿ â ñâÿçè ñ óñòàðåâàíèåì èíôîðìàöèè |
mov [root_read], 0 |
mov [flp_fat], 0 |
ret |
FDDMotorOFF_A: |
mov DX, 3F2h;ïîðò óïðàâëåíèÿ äâèãàòåëÿìè |
mov AL, 0Ch ; Floppy A |
out DX, AL |
ret |
FDDMotorOFF_B: |
mov DX, 3F2h;ïîðò óïðàâëåíèÿ äâèãàòåëÿìè |
mov AL, 5h ; Floppy B |
out DX, AL |
ret |
;******************************* |
;* ÐÅÊÀËÈÁÐÎÂÊÀ ÄÈÑÊÎÂÎÄÀ "A:" * |
;******************************* |
RecalibrateFDD: |
pusha |
call save_timer_fdd_motor |
; Ïîäàòü êîìàíäó "Ðåêàëèáðîâêà" |
mov AL, 07h |
call FDCDataOutput |
mov AL, 00h |
call FDCDataOutput |
; Îæèäàòü çàâåðøåíèÿ îïåðàöèè |
call WaitFDCInterrupt |
; cmp [FDC_Status],0 |
; je no_fdc_status_error |
; mov [flp_status],0 |
;no_fdc_status_error: |
call save_timer_fdd_motor |
popa |
ret |
;***************************************************** |
;* ÏÎÈÑÊ ÄÎÐÎÆÊÈ * |
;* Ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå ïåðåìåííûå: * |
;* FDD_Track - íîìåð äîðîæêè (0-79); * |
;* FDD_Head - íîìåð ãîëîâêè (0-1). * |
;* Ðåçóëüòàò îïåðàöèè çàíîñèòñÿ â FDC_Status. * |
;***************************************************** |
SeekTrack: |
pusha |
call save_timer_fdd_motor |
; Ïîäàòü êîìàíäó "Ïîèñê" |
mov AL, 0Fh |
call FDCDataOutput |
; Ïåðåäàòü áàéò íîìåðà ãîëîâêè/íàêîïèòåë |
mov AL, [FDD_Head] |
shl AL, 2 |
call FDCDataOutput |
; Ïåðåäàòü áàéò íîìåðà äîðîæêè |
mov AL, [FDD_Track] |
call FDCDataOutput |
; Îæèäàòü çàâåðøåíèÿ îïåðàöèè |
call WaitFDCInterrupt |
cmp [FDC_Status], FDC_Normal |
jne @@Exit |
; Ñîõðàíèòü ðåçóëüòàò ïîèñêà |
mov AL, 08h |
call FDCDataOutput |
call FDCDataInput |
mov [FDC_ST0], AL |
call FDCDataInput |
mov [FDC_C], AL |
; Ïðîâåðèòü ðåçóëüòàò ïîèñêà |
; Ïîèñê çàâåðøåí? |
test [FDC_ST0], 100000b |
je @@Err |
; Çàäàííûé òðåê íàéäåí? |
mov AL, [FDC_C] |
cmp AL, [FDD_Track] |
jne @@Err |
; Íîìåð ãîëîâêè ñîâïàäàåò ñ çàäàííûì? |
mov AL, [FDC_ST0] |
and AL, 100b |
shr AL, 2 |
cmp AL, [FDD_Head] |
jne @@Err |
; Îïåðàöèÿ çàâåðøåíà óñïåøíî |
mov [FDC_Status], FDC_Normal |
jmp @@Exit |
@@Err: ; Òðåê íå íàéäåí |
mov [FDC_Status], FDC_TrackNotFound |
; mov [flp_status],0 |
@@Exit: |
call save_timer_fdd_motor |
popa |
ret |
;******************************************************* |
;* ×ÒÅÍÈÅ ÑÅÊÒÎÐÀ ÄÀÍÍÛÕ * |
;* Ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå ïåðåìåííûå: * |
;* FDD_Track - íîìåð äîðîæêè (0-79); * |
;* FDD_Head - íîìåð ãîëîâêè (0-1); * |
;* FDD_Sector - íîìåð ñåêòîðà (1-18). * |
;* Ðåçóëüòàò îïåðàöèè çàíîñèòñÿ â FDC_Status. * |
;*  ñëó÷àå óñïåøíîãî âûïîëíåíèÿ îïåðàöèè ÷òåíèÿ * |
;* ñîäåðæèìîå ñåêòîðà áóäåò çàíåñåíî â FDD_DataBuffer. * |
;******************************************************* |
ReadSector: |
pushad |
call save_timer_fdd_motor |
; Óñòàíîâèòü ñêîðîñòü ïåðåäà÷è 500 Êáàéò/ñ |
mov AX, 0 |
mov DX, 03F7h |
out DX, AL |
; Èíèöèàëèçèðîâàòü êàíàë ïðÿìîãî äîñòóïà ê ïàìÿòè |
mov [dmamode], 0x46 |
call Init_FDC_DMA |
; Ïîäàòü êîìàíäó "×òåíèå äàííûõ" |
mov AL, 0E6h ;÷òåíèå â ìóëüòèòðåêîâîì ðåæèìå |
call FDCDataOutput |
mov AL, [FDD_Head] |
shl AL, 2 |
call FDCDataOutput |
mov AL, [FDD_Track] |
call FDCDataOutput |
mov AL, [FDD_Head] |
call FDCDataOutput |
mov AL, [FDD_Sector] |
call FDCDataOutput |
mov AL, 2 ;êîä ðàçìåðà ñåêòîðà (512 áàéò) |
call FDCDataOutput |
mov AL, 18 ;+1; 3Fh ;÷èñëî ñåêòîðîâ íà äîðîæêå |
call FDCDataOutput |
mov AL, 1Bh ;çíà÷åíèå GPL |
call FDCDataOutput |
mov AL, 0FFh;çíà÷åíèå DTL |
call FDCDataOutput |
; Îæèäàåì ïðåðûâàíèå ïî çàâåðøåíèè îïåðàöèè |
call WaitFDCInterrupt |
cmp [FDC_Status], FDC_Normal |
jne @@Exit_1 |
; Ñ÷èòûâàåì ñòàòóñ çàâåðøåíèÿ îïåðàöèè |
call GetStatusInfo |
test [FDC_ST0], 11011000b |
jnz @@Err_1 |
mov [FDC_Status], FDC_Normal |
jmp @@Exit_1 |
@@Err_1: |
mov [FDC_Status], FDC_SectorNotFound |
; mov [flp_status],0 |
@@Exit_1: |
call save_timer_fdd_motor |
popad |
ret |
;******************************************************* |
;* ×ÒÅÍÈÅ ÑÅÊÒÎÐÀ (Ñ ÏÎÂÒÎÐÅÍÈÅÌ ÎÏÅÐÀÖÈÈ ÏÐÈ ÑÁÎÅ) * |
;* Ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå ïåðåìåííûå: * |
;* FDD_Track - íîìåð äîðîæêè (0-79); * |
;* FDD_Head - íîìåð ãîëîâêè (0-1); * |
;* FDD_Sector - íîìåð ñåêòîðà (1-18). * |
;* Ðåçóëüòàò îïåðàöèè çàíîñèòñÿ â FDC_Status. * |
;*  ñëó÷àå óñïåøíîãî âûïîëíåíèÿ îïåðàöèè ÷òåíèÿ * |
;* ñîäåðæèìîå ñåêòîðà áóäåò çàíåñåíî â FDD_DataBuffer. * |
;******************************************************* |
ReadSectWithRetr: |
pusha |
; Îáíóëèòü ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ðåêàëèáðîâêè |
mov [RecalRepCounter], 0 |
@@TryAgain: |
; Îáíóëèòü ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ÷òåíè |
mov [ReadRepCounter], 0 |
@@ReadSector_1: |
call ReadSector |
cmp [FDC_Status], 0 |
je @@Exit_2 |
cmp [FDC_Status], 1 |
je @@Err_3 |
; Òðîåêðàòíîå ïîâòîðåíèå ÷òåíè |
inc [ReadRepCounter] |
cmp [ReadRepCounter], 3 |
jb @@ReadSector_1 |
; Òðîåêðàòíîå ïîâòîðåíèå ðåêàëèáðîâêè |
call RecalibrateFDD |
call SeekTrack |
inc [RecalRepCounter] |
cmp [RecalRepCounter], 3 |
jb @@TryAgain |
; mov [flp_status],0 |
@@Exit_2: |
popa |
ret |
@@Err_3: |
mov [flp_status], 0 |
popa |
ret |
;******************************************************* |
;* ÇÀÏÈÑÜ ÑÅÊÒÎÐÀ ÄÀÍÍÛÕ * |
;* Ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå ïåðåìåííûå: * |
;* FDD_Track - íîìåð äîðîæêè (0-79); * |
;* FDD_Head - íîìåð ãîëîâêè (0-1); * |
;* FDD_Sector - íîìåð ñåêòîðà (1-18). * |
;* Ðåçóëüòàò îïåðàöèè çàíîñèòñÿ â FDC_Status. * |
;*  ñëó÷àå óñïåøíîãî âûïîëíåíèÿ îïåðàöèè çàïèñè * |
;* ñîäåðæèìîå FDD_DataBuffer áóäåò çàíåñåíî â ñåêòîð. * |
;******************************************************* |
WriteSector: |
pushad |
call save_timer_fdd_motor |
; Óñòàíîâèòü ñêîðîñòü ïåðåäà÷è 500 Êáàéò/ñ |
mov AX, 0 |
mov DX, 03F7h |
out DX, AL |
; Èíèöèàëèçèðîâàòü êàíàë ïðÿìîãî äîñòóïà ê ïàìÿòè |
mov [dmamode], 0x4A |
call Init_FDC_DMA |
; Ïîäàòü êîìàíäó "Çàïèñü äàííûõ" |
mov AL, 0xC5 ;0x45 ;çàïèñü â ìóëüòèòðåêîâîì ðåæèìå |
call FDCDataOutput |
mov AL, [FDD_Head] |
shl AL, 2 |
call FDCDataOutput |
mov AL, [FDD_Track] |
call FDCDataOutput |
mov AL, [FDD_Head] |
call FDCDataOutput |
mov AL, [FDD_Sector] |
call FDCDataOutput |
mov AL, 2 ;êîä ðàçìåðà ñåêòîðà (512 áàéò) |
call FDCDataOutput |
mov AL, 18; 3Fh ;÷èñëî ñåêòîðîâ íà äîðîæêå |
call FDCDataOutput |
mov AL, 1Bh ;çíà÷åíèå GPL |
call FDCDataOutput |
mov AL, 0FFh;çíà÷åíèå DTL |
call FDCDataOutput |
; Îæèäàåì ïðåðûâàíèå ïî çàâåðøåíèè îïåðàöèè |
call WaitFDCInterrupt |
cmp [FDC_Status], FDC_Normal |
jne @@Exit_3 |
; Ñ÷èòûâàåì ñòàòóñ çàâåðøåíèÿ îïåðàöèè |
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 |
;******************************************************* |
;* ÇÀÏÈÑÜ ÑÅÊÒÎÐÀ (Ñ ÏÎÂÒÎÐÅÍÈÅÌ ÎÏÅÐÀÖÈÈ ÏÐÈ ÑÁÎÅ) * |
;* Ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå ïåðåìåííûå: * |
;* FDD_Track - íîìåð äîðîæêè (0-79); * |
;* FDD_Head - íîìåð ãîëîâêè (0-1); * |
;* FDD_Sector - íîìåð ñåêòîðà (1-18). * |
;* Ðåçóëüòàò îïåðàöèè çàíîñèòñÿ â FDC_Status. * |
;*  ñëó÷àå óñïåøíîãî âûïîëíåíèÿ îïåðàöèè çàïèñè * |
;* ñîäåðæèìîå FDD_DataBuffer áóäåò çàíåñåíî â ñåêòîð. * |
;******************************************************* |
WriteSectWithRetr: |
pusha |
; Îáíóëèòü ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ðåêàëèáðîâêè |
mov [RecalRepCounter], 0 |
@@TryAgain_1: |
; Îáíóëèòü ñ÷åò÷èê ïîâòîðåíèÿ îïåðàöèè ÷òåíè |
mov [ReadRepCounter], 0 |
@@WriteSector_1: |
call WriteSector |
cmp [FDC_Status], 0 |
je @@Exit_4 |
cmp [FDC_Status], 1 |
je @@Err_4 |
; Òðîåêðàòíîå ïîâòîðåíèå ÷òåíè |
inc [ReadRepCounter] |
cmp [ReadRepCounter], 3 |
jb @@WriteSector_1 |
; Òðîåêðàòíîå ïîâòîðåíèå ðåêàëèáðîâêè |
call RecalibrateFDD |
call SeekTrack |
inc [RecalRepCounter] |
cmp [RecalRepCounter], 3 |
jb @@TryAgain_1 |
@@Exit_4: |
popa |
ret |
@@Err_4: |
mov [flp_status], 0 |
popa |
ret |
;********************************************* |
;* ÏÎËÓ×ÈÒÜ ÈÍÔÎÐÌÀÖÈÞ Î ÐÅÇÓËÜÒÀÒÅ ÎÏÅÐÀÖÈÈ * |
;********************************************* |
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 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev/rd.inc |
---|
0,0 → 1,2273 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; RAMDISK functions ;; |
;; (C) 2004 Ville Turjanmaa, License: GPL ;; |
;; Addings by M.Lisovin ;; |
;; LFN support by diamond ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
; calculate fat chain |
calculatefatchain: |
pushad |
mov esi, RAMDISK+512 |
mov edi, RAMDISK_FAT |
fcnew: |
mov eax, dword [esi] |
mov ebx, dword [esi+4] |
mov ecx, dword [esi+8] |
mov edx, ecx |
shr edx, 4;8 ok |
shr dx, 4;7 ok |
xor ch, ch |
shld ecx, ebx, 20;6 ok |
shr cx, 4;5 ok |
shld ebx, eax, 12 |
and ebx, 0x0fffffff;4 ok |
shr bx, 4;3 ok |
shl eax, 4 |
and eax, 0x0fffffff;2 ok |
shr ax, 4;1 ok |
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, RAMDISK_FAT+2856*2;2849 clusters |
jnz fcnew |
popad |
ret |
restorefatchain: ; restore fat chain |
pushad |
mov esi, RAMDISK_FAT |
mov edi, RAMDISK+512 |
fcnew2: |
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 edi, RAMDISK+512+4278;4274 bytes - all used FAT |
jb fcnew2 |
mov esi, RAMDISK+512 ; duplicate fat chain |
mov edi, RAMDISK+512+0x1200 |
mov ecx, 1069;4274/4 |
cld |
rep movsd |
popad |
ret |
ramdisk_free_space: |
;--------------------------------------------- |
; |
; returns free space in edi |
; rewr.by Mihasik |
;--------------------------------------------- |
push eax ebx ecx |
mov edi, RAMDISK_FAT;start of FAT |
xor ax, ax;Free cluster=0x0000 in FAT |
xor ebx, ebx;counter |
mov ecx, 2849;2849 clusters |
cld |
rdfs1: |
repne scasw |
jnz rdfs2 ;if last cluster not 0 |
inc ebx |
test ecx, ecx |
jnz rdfs1 |
rdfs2: |
shl ebx, 9;free clusters*512 |
mov edi, ebx |
pop ecx ebx eax |
ret |
expand_filename: |
;--------------------------------------------- |
; |
; exapand filename with '.' to 11 character |
; eax - pointer to filename |
;--------------------------------------------- |
push esi edi ebx |
mov edi, esp ; check for '.' in the name |
add edi, 12+8 |
mov esi, eax |
mov eax, edi |
mov [eax+0], dword ' ' |
mov [eax+4], dword ' ' |
mov [eax+8], dword ' ' |
flr1: |
cmp [esi], byte '.' |
jne flr2 |
mov edi, eax |
add edi, 7 |
jmp flr3 |
flr2: |
mov bl, [esi] |
mov [edi], bl |
flr3: |
inc esi |
inc edi |
mov ebx, eax |
add ebx, 11 |
cmp edi, ebx |
jbe flr1 |
pop ebx edi esi |
ret |
fileread: |
;---------------------------------------------------------------- |
; |
; fileread - sys floppy |
; |
; eax points to filename 11 chars |
; ebx first wanted block ; 1+ ; if 0 then set to 1 |
; ecx number of blocks to read ; 1+ ; if 0 then set to 1 |
; edx mem location to return data |
; esi length of filename 12*X 0=root |
; |
; ret ebx = size or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
test ebx, ebx;if ebx=0 - set to 1 |
jnz frfl5 |
inc ebx |
frfl5: |
test ecx, ecx;if ecx=0 - set to 1 |
jnz frfl6 |
inc ecx |
frfl6: |
test esi, esi ; return ramdisk root |
jnz fr_noroot ;if not root |
cmp ebx, 14 ;14 clusters=root dir |
ja oorr |
cmp ecx, 14 |
ja oorr |
jmp fr_do |
oorr: |
mov eax, 5 ;out of root range (fnf) |
xor ebx, ebx |
dec ebx ;0xffffffff |
ret |
fr_do: ;reading rootdir |
mov edi, edx |
dec ebx |
push edx |
mov edx, ecx |
add edx, ebx |
cmp edx, 15 ;ebx+ecx=14+1 |
pushf |
jbe fr_do1 |
sub edx, 14 |
sub ecx, edx |
fr_do1: |
shl ebx, 9 |
mov esi, RAMDISK+512*19 |
add esi, ebx |
shl ecx, 7 |
cld |
rep movsd |
popf |
pop edx |
jae fr_do2 |
xor eax, eax; ok read |
xor ebx, ebx |
ret |
fr_do2: ;if last cluster |
mov eax, 6;end of file |
xor ebx, ebx |
ret |
fr_noroot: |
sub esp, 32 |
call expand_filename |
dec ebx |
push eax |
push eax ebx ecx edx esi edi |
call rd_findfile |
je fifound |
add esp, 32+28 ;if file not found |
ret |
fifound: |
mov ebx, [edi-11+28] ;file size |
mov [esp+20], ebx |
mov [esp+24], ebx |
add edi, 0xf |
movzx eax, word [edi] |
mov edi, eax ;edi=cluster |
frnew: |
add eax, 31 ;bootsector+2*fat+filenames |
shl eax, 9 ;*512 |
add eax, RAMDISK ;image base |
mov ebx, [esp+8] |
mov ecx, 512 ;[esp+4] |
cmp [esp+16], dword 0 ; wanted cluster ? |
jne frfl7 |
call memmove |
add [esp+8], dword 512 |
dec dword [esp+12] ; last wanted cluster ? |
je frnoread |
jmp frfl8 |
frfl7: |
dec dword [esp+16] |
frfl8: |
movzx eax, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT |
mov edi, eax |
cmp edi, 4095 ;eof - cluster |
jz frnoread2 |
cmp [esp+24], dword 512 ;eof - size |
jb frnoread |
sub [esp+24], dword 512 |
jmp frnew |
frnoread2: |
cmp [esp+16], dword 0 ; eof without read ? |
je frnoread |
pop edi esi edx ecx |
add esp, 4 |
pop ebx ; ebx <- eax : size of file |
add esp, 36 |
mov eax, 6 ; end of file |
ret |
frnoread: |
pop edi esi edx ecx |
add esp, 4 |
pop ebx ; ebx <- eax : size of file |
add esp, 36 |
xor eax, eax;read ok |
ret |
rd_findfile: |
;by Mihasik |
;IN: eax - pointer to filename OUT: filestring+11 in edi or notZero in flags and fnf in eax,ebx |
mov edi, RAMDISK+512*18+512;Point at directory |
cld |
rd_newsearch: |
mov esi, eax |
mov ecx, 11 |
rep cmpsb |
je rd_ff |
add cl, 21 |
add edi, ecx |
cmp edi, RAMDISK+512*33 |
jb rd_newsearch |
mov eax, 5 ;if file not found - eax=5 |
xor ebx, ebx |
dec ebx ;ebx=0xffffffff and zf=0 |
rd_ff: |
ret |
; \begin{diamond} |
uni2ansi_str: |
; convert UNICODE zero-terminated string to ASCII-string (codepage 866) |
; in: esi->source, edi->buffer (may be esi=edi) |
; destroys: eax,esi,edi |
lodsw |
test ax, ax |
jz .done |
cmp ax, 0x80 |
jb .ascii |
cmp ax, 0x401 |
jz .yo1 |
cmp ax, 0x451 |
jz .yo2 |
cmp ax, 0x410 |
jb .unk |
cmp ax, 0x440 |
jb .rus1 |
cmp ax, 0x450 |
jb .rus2 |
.unk: |
mov al, '_' |
jmp .doit |
.yo1: |
mov al, 'ð' |
jmp .doit |
.yo2: |
mov al, 'ñ' |
jmp .doit |
.rus1: |
; 0x410-0x43F -> 0x80-0xAF |
add al, 0x70 |
jmp .doit |
.rus2: |
; 0x440-0x44F -> 0xE0-0xEF |
add al, 0xA0 |
.ascii: |
.doit: |
stosb |
jmp uni2ansi_str |
.done: |
mov byte [edi], 0 |
ret |
ansi2uni_char: |
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding |
mov ah, 0 |
; 0x00-0x7F - trivial map |
cmp al, 0x80 |
jb .ret |
; 0x80-0xAF -> 0x410-0x43F |
cmp al, 0xB0 |
jae @f |
add ax, 0x410-0x80 |
.ret: |
ret |
@@: |
; 0xE0-0xEF -> 0x440-0x44F |
cmp al, 0xE0 |
jb .unk |
cmp al, 0xF0 |
jae @f |
add ax, 0x440-0xE0 |
ret |
; 0xF0 -> 0x401 |
; 0xF1 -> 0x451 |
@@: |
cmp al, 'ð' |
jz .yo1 |
cmp al, 'ñ' |
jz .yo2 |
.unk: |
mov al, '_' ; ah=0 |
ret |
.yo1: |
mov ax, 0x401 |
ret |
.yo2: |
mov ax, 0x451 |
ret |
char_toupper: |
; convert character to uppercase, using cp866 encoding |
; in: al=symbol |
; out: al=converted symbol |
cmp al, 'a' |
jb .ret |
cmp al, 'z' |
jbe .az |
cmp al, 'ñ' |
jz .yo1 |
cmp al, ' ' |
jb .ret |
cmp al, 'à' |
jb .rus1 |
cmp al, 'ï' |
ja .ret |
; 0xE0-0xEF -> 0x90-0x9F |
sub al, 'à'-'' |
.ret: |
ret |
.rus1: |
; 0xA0-0xAF -> 0x80-0x8F |
.az: |
and al, not 0x20 |
ret |
.yo1: |
; 0xF1 -> 0xF0 |
dec ax |
ret |
fat_get_name: |
; in: edi->FAT entry |
; out: CF=1 - no valid entry |
; else CF=0 and ebp->ASCIIZ-name |
; (maximum length of filename is 255 (wide) symbols without trailing 0, |
; but implementation requires buffer 261 words) |
; destroys eax |
cmp byte [edi], 0 |
jz .no |
cmp byte [edi], 0xE5 |
jnz @f |
.no: |
stc |
ret |
@@: |
cmp byte [edi+11], 0xF |
jz .longname |
test byte [edi+11], 8 |
jnz .no |
push ecx |
push edi ebp |
test byte [ebp-4], 1 |
jnz .unicode_short |
mov eax, [edi] |
mov ecx, [edi+4] |
mov [ebp], eax |
mov [ebp+4], ecx |
mov ecx, 8 |
@@: |
cmp byte [ebp+ecx-1], ' ' |
loope @b |
mov eax, [edi+8] |
cmp al, ' ' |
je .done |
shl eax, 8 |
mov al, '.' |
lea ebp, [ebp+ecx+1] |
mov [ebp], eax |
mov ecx, 3 |
@@: |
rol eax, 8 |
cmp al, ' ' |
jne .done |
loop @b |
dec ebp |
.done: |
and byte [ebp+ecx+1], 0 ; CF=0 |
pop ebp edi ecx |
ret |
.unicode_short: |
mov ecx, 8 |
push ecx |
@@: |
mov al, [edi] |
inc edi |
call ansi2uni_char |
mov [ebp], ax |
inc ebp |
inc ebp |
loop @b |
pop ecx |
@@: |
cmp word [ebp-2], ' ' |
jnz @f |
dec ebp |
dec ebp |
loop @b |
@@: |
mov word [ebp], '.' |
inc ebp |
inc ebp |
mov ecx, 3 |
push ecx |
@@: |
mov al, [edi] |
inc edi |
call ansi2uni_char |
mov [ebp], ax |
inc ebp |
inc ebp |
loop @b |
pop ecx |
@@: |
cmp word [ebp-2], ' ' |
jnz @f |
dec ebp |
dec ebp |
loop @b |
dec ebp |
dec ebp |
@@: |
and word [ebp], 0 ; CF=0 |
pop ebp edi ecx |
ret |
.longname: |
; LFN |
mov al, byte [edi] |
and eax, 0x3F |
dec eax |
cmp al, 20 |
jae .no ; ignore invalid entries |
mov word [ebp+260*2], 0 ; force null-terminating for orphans |
imul eax, 13*2 |
add ebp, eax |
test byte [edi], 0x40 |
jz @f |
mov word [ebp+13*2], 0 |
@@: |
push eax |
; now copy name from edi to ebp ... |
mov eax, [edi+1] |
mov [ebp], eax ; symbols 1,2 |
mov eax, [edi+5] |
mov [ebp+4], eax ; 3,4 |
mov eax, [edi+9] |
mov [ebp+8], ax ; 5 |
mov eax, [edi+14] |
mov [ebp+10], eax ; 6,7 |
mov eax, [edi+18] |
mov [ebp+14], eax ; 8,9 |
mov eax, [edi+22] |
mov [ebp+18], eax ; 10,11 |
mov eax, [edi+28] |
mov [ebp+22], eax ; 12,13 |
; ... done |
pop eax |
sub ebp, eax |
test eax, eax |
jz @f |
; if this is not first entry, more processing required |
stc |
ret |
@@: |
; if this is first entry: |
test byte [ebp-4], 1 |
jnz .ret |
; buffer at ebp contains UNICODE name, convert it to ANSI |
push esi edi |
mov esi, ebp |
mov edi, ebp |
call uni2ansi_str |
pop edi esi |
.ret: |
clc |
ret |
fat_compare_name: |
; compares ASCIIZ-names, case-insensitive (cp866 encoding) |
; in: esi->name, ebp->name |
; out: if names match: ZF=1 and esi->next component of name |
; else: ZF=0, esi is not changed |
; destroys eax |
push ebp esi |
.loop: |
mov al, [ebp] |
inc ebp |
call char_toupper |
push eax |
lodsb |
call char_toupper |
cmp al, [esp] |
jnz .done |
pop eax |
test al, al |
jnz .loop |
dec esi |
pop eax |
pop ebp |
xor eax, eax ; set ZF flag |
ret |
.done: |
cmp al, '/' |
jnz @f |
cmp byte [esp], 0 |
jnz @f |
mov [esp+4], esi |
@@: |
pop eax |
pop esi ebp |
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 |
; destroys eax |
mov eax, [ebp-4] |
mov [esi+4], eax ; ASCII/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 |
push ecx edi |
lea edi, [esi+40] |
mov esi, ebp |
test byte [esi-4], 1 |
jz .ansi |
mov ecx, 260/2 |
rep movsd |
mov [edi-2], ax |
@@: |
mov esi, edi |
pop edi ecx |
.ret: |
ret |
.ansi: |
mov ecx, 264/4 |
rep movsd |
mov [edi-1], al |
jmp @b |
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 |
ramdisk_root_first: |
mov edi, RAMDISK+512*19 |
clc |
ret |
ramdisk_root_next: |
add edi, 0x20 |
cmp edi, RAMDISK+512*33 |
cmc |
ret |
ramdisk_root_extend_dir: |
stc |
ret |
uglobal |
; this is for delete support |
rd_prev_sector dd ? |
rd_prev_prev_sector dd ? |
endg |
ramdisk_notroot_next: |
add edi, 0x20 |
test edi, 0x1FF |
jz ramdisk_notroot_next_sector |
ret ; CF=0 |
ramdisk_notroot_next_sector: |
push ecx |
mov ecx, [eax] |
push [rd_prev_sector] |
pop [rd_prev_prev_sector] |
mov [rd_prev_sector], ecx |
mov ecx, [ecx*2+RAMDISK_FAT] |
and ecx, 0xFFF |
cmp ecx, 2849 |
jae ramdisk_notroot_first.err2 |
mov [eax], ecx |
pop ecx |
ramdisk_notroot_first: |
mov eax, [eax] |
cmp eax, 2 |
jb .err |
cmp eax, 2849 |
jae .err |
shl eax, 9 |
lea edi, [eax+(31 shl 9)+RAMDISK] |
clc |
ret |
.err2: |
pop ecx |
.err: |
stc |
ret |
ramdisk_notroot_next_write: |
test edi, 0x1FF |
jz ramdisk_notroot_next_sector |
ramdisk_root_next_write: |
ret |
ramdisk_notroot_extend_dir: |
pusha |
xor eax, eax |
mov edi, RAMDISK_FAT |
mov ecx, 2849 |
repnz scasw |
jnz .notfound |
mov word [edi-2], 0xFFF |
sub edi, RAMDISK_FAT |
shr edi, 1 |
dec edi |
mov eax, [esp+28] |
mov ecx, [eax] |
mov [RAMDISK_FAT+ecx*2], di |
mov [eax], edi |
shl edi, 9 |
add edi, (31 shl 9)+RAMDISK |
mov [esp], edi |
xor eax, eax |
mov ecx, 128 |
rep stosd |
popa |
clc |
ret |
.notfound: |
popa |
stc |
ret |
rd_find_lfn: |
; in: esi+ebp -> name |
; out: CF=1 - file not found |
; else CF=0 and edi->direntry |
push esi edi |
push 0 |
push ramdisk_root_first |
push ramdisk_root_next |
.loop: |
call fat_find_lfn |
jc .notfound |
cmp byte [esi], 0 |
jz .found |
.continue: |
test byte [edi+11], 10h |
jz .notfound |
movzx eax, word [edi+26] |
mov [esp+8], eax |
mov dword [esp+4], ramdisk_notroot_first |
mov dword [esp], ramdisk_notroot_next |
test eax, eax |
jnz .loop |
mov dword [esp+4], ramdisk_root_first |
mov dword [esp], ramdisk_notroot_next |
jmp .loop |
.notfound: |
add esp, 12 |
pop edi esi |
stc |
ret |
.found: |
test ebp, ebp |
jz @f |
mov esi, ebp |
xor ebp, ebp |
jmp .continue |
@@: |
mov eax, [esp+8] |
add esp, 16 ; CF=0 |
pop esi |
ret |
;---------------------------------------------------------------- |
; |
; fs_RamdiskRead - LFN variant for reading sys floppy |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = bytes read or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_RamdiskRead: |
cmp byte [esi], 0 |
jnz @f |
or ebx, -1 |
mov eax, 10 ; access denied |
ret |
@@: |
push edi |
call rd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, 5 ; file not found |
ret |
.found: |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
xor ebx, ebx |
.reteof: |
mov eax, 6 ; EOF |
pop edi |
ret |
@@: |
mov ebx, [ebx] |
.l1: |
push ecx edx |
push 0 |
mov eax, [edi+28] |
sub eax, ebx |
jb .eof |
cmp eax, ecx |
jae @f |
mov ecx, eax |
mov byte [esp], 6 ; EOF |
@@: |
movzx edi, word [edi+26] ; cluster |
.new: |
jecxz .done |
test edi, edi |
jz .eof |
cmp edi, 0xFF8 |
jae .eof |
lea eax, [edi+31] ; bootsector+2*fat+filenames |
shl eax, 9 ; *512 |
add eax, RAMDISK ; image base |
; now eax points to data of cluster |
sub ebx, 512 |
jae .skip |
lea eax, [eax+ebx+512] |
neg ebx |
push ecx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
mov ebx, edx |
call memmove |
add edx, ecx |
sub [esp], ecx |
pop ecx |
xor ebx, ebx |
.skip: |
movzx edi, word [edi*2+RAMDISK_FAT] ; find next cluster from FAT |
jmp .new |
.eof: |
mov ebx, edx |
pop eax edx ecx |
sub ebx, edx |
jmp .reteof |
.done: |
mov ebx, edx |
pop eax edx ecx edi |
sub ebx, edx |
ret |
;---------------------------------------------------------------- |
; |
; fs_RamdiskReadFolder - LFN variant for reading sys floppy folder |
; |
; esi points to filename; only root is folder on ramdisk |
; ebx pointer to structure 32-bit number = first wanted block |
; & flags (bitfields) |
; flags: bit 0: 0=ANSI names, 1=UNICODE names |
; ecx number of blocks to read, 0+ |
; edx mem location to return data |
; |
; ret ebx = size or 0xffffffff file not found |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_RamdiskReadFolder: |
push edi |
cmp byte [esi], 0 |
jz .root |
call rd_find_lfn |
jnc .found |
pop edi |
or ebx, -1 |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
.found: |
test byte [edi+11], 0x10 |
jnz .found_dir |
pop edi |
or ebx, -1 |
mov eax, ERROR_ACCESS_DENIED |
ret |
.found_dir: |
movzx eax, word [edi+26] |
add eax, 31 |
push 0 |
jmp .doit |
.root: |
mov eax, 19 |
push 14 |
.doit: |
push esi ecx ebp |
sub esp, 262*2 ; reserve space for LFN |
mov ebp, esp |
push dword [ebx+4] ; for fat_get_name: read ANSI/UNICODE names |
mov ebx, [ebx] |
; init header |
push eax ecx |
mov edi, edx |
mov ecx, 32/4 |
xor eax, eax |
rep stosd |
mov byte [edx], 1 ; version |
pop ecx eax |
mov esi, edi ; esi points to block of data of folder entry (BDFE) |
.main_loop: |
mov edi, eax |
shl edi, 9 |
add edi, RAMDISK |
push eax |
.l1: |
call fat_get_name |
jc .l2 |
cmp byte [edi+11], 0xF |
jnz .do_bdfe |
add edi, 0x20 |
test edi, 0x1FF |
jnz .do_bdfe |
pop eax |
inc eax |
dec byte [esp+262*2+16] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+RAMDISK_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+16], 0 |
@@: |
mov edi, eax |
shl edi, 9 |
add edi, RAMDISK |
push eax |
.do_bdfe: |
inc dword [edx+8] ; new file found |
dec ebx |
jns .l2 |
dec ecx |
js .l2 |
inc dword [edx+4] ; new file block copied |
call fat_entry_to_bdfe |
.l2: |
add edi, 0x20 |
test edi, 0x1FF |
jnz .l1 |
pop eax |
inc eax |
dec byte [esp+262*2+16] |
jz .done |
jns @f |
; read next sector from FAT |
mov eax, [(eax-31-1)*2+RAMDISK_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
jae .done |
add eax, 31 |
mov byte [esp+262*2+16], 0 |
@@: |
jmp .main_loop |
.done: |
add esp, 262*2+4 |
pop ebp |
mov ebx, [edx+4] |
xor eax, eax |
dec ecx |
js @f |
mov al, ERROR_END_OF_FILE |
@@: |
pop ecx esi edi edi |
ret |
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->(long) name |
; out: CF set <=> legal |
; destroys eax |
push esi |
xor eax, eax |
@@: |
lodsb |
test al, al |
jz .done |
cmp al, 80h |
jae .big |
test [fat_legal_chars+eax], 1 |
jnz @b |
.err: |
pop esi |
clc |
ret |
.big: |
; 0x80-0xAF, 0xE0-0xEF |
cmp al, 0xB0 |
jb @b |
cmp al, 0xE0 |
jb .err |
cmp al, 0xF0 |
jb @b |
jmp .err |
.done: |
sub esi, [esp] |
cmp esi, 257 |
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 |
;clc ; automatically |
ret |
.err: |
pop edi |
popad |
stc |
ret |
fat_gen_short_name: |
; in: esi->long name |
; edi->buffer (8+3=11 chars) |
; out: buffer filled |
pushad |
mov eax, ' ' |
push edi |
stosd |
stosd |
stosd |
pop edi |
xor eax, eax |
push 8 |
pop ebx |
lea ecx, [edi+8] |
.loop: |
lodsb |
test al, al |
jz .done |
call char_toupper |
cmp al, ' ' |
jz .space |
cmp al, 80h |
ja .big |
test [fat_legal_chars+eax], 2 |
jnz .symbol |
.inv_symbol: |
mov al, '_' |
or bh, 1 |
.symbol: |
cmp al, '.' |
jz .dot |
.normal_symbol: |
dec bl |
jns .store |
mov bl, 0 |
.space: |
or bh, 1 |
jmp .loop |
.store: |
stosb |
jmp .loop |
.big: |
cmp al, 0xB0 |
jb .normal_symbol |
cmp al, 0xE0 |
jb .inv_symbol |
cmp al, 0xF0 |
jb .normal_symbol |
jmp .inv_symbol |
.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 |
;---------------------------------------------------------------- |
; |
; fs_RamdiskRewrite - LFN variant for writing ramdisk |
; fs_RamdiskCreateFolder - create folder on ramdisk |
; |
; esi points to file/folder name |
; ebx ignored (reserved) |
; ecx number of bytes to write, 0+ (ignored for folders) |
; edx mem location to data (ignored for folders) |
; |
; ret ebx = number of written bytes |
; eax = 0 ok read or other = errormsg |
; |
;-------------------------------------------------------------- |
@@: |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
fs_RamdiskCreateFolder: |
mov al, 1 ; create folder |
jmp fs_RamdiskRewrite.common |
fs_RamdiskRewrite: |
xor eax, eax ; create file |
.common: |
cmp byte [esi], 0 |
jz @b |
pushad |
xor edi, edi |
push esi |
test ebp, ebp |
jz @f |
mov esi, ebp |
@@: |
lodsb |
test al, al |
jz @f |
cmp al, '/' |
jnz @b |
lea edi, [esi-1] |
jmp @b |
@@: |
pop esi |
test edi, edi |
jnz .noroot |
test ebp, ebp |
jnz .hasebp |
push ramdisk_root_extend_dir |
push ramdisk_root_next_write |
push edi |
push ramdisk_root_first |
push ramdisk_root_next |
jmp .common1 |
.hasebp: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [ebp], 0 |
jz .ret1 |
push ebp |
xor ebp, ebp |
call rd_find_lfn |
pop esi |
jc .notfound0 |
jmp .common0 |
.noroot: |
mov eax, ERROR_ACCESS_DENIED |
cmp byte [edi+1], 0 |
jz .ret1 |
; check existence |
mov byte [edi], 0 |
push edi |
call rd_find_lfn |
pop esi |
mov byte [esi], '/' |
jnc @f |
.notfound0: |
mov eax, ERROR_FILE_NOT_FOUND |
.ret1: |
mov [esp+28], eax |
popad |
xor ebx, ebx |
ret |
@@: |
inc esi |
.common0: |
test byte [edi+11], 0x10 ; must be directory |
mov eax, ERROR_ACCESS_DENIED |
jz .ret1 |
movzx ebp, word [edi+26] ; ebp=cluster |
mov eax, ERROR_FAT_TABLE |
cmp ebp, 2 |
jb .ret1 |
cmp ebp, 2849 |
jae .ret1 |
push ramdisk_notroot_extend_dir |
push ramdisk_notroot_next_write |
push ebp |
push ramdisk_notroot_first |
push ramdisk_notroot_next |
.common1: |
call fat_find_lfn |
jc .notfound |
; found |
test byte [edi+11], 10h |
jz .exists_file |
; found directory; if we are creating directory, return OK, |
; if we are creating file, say "access denied" |
add esp, 20 |
popad |
test al, al |
mov eax, ERROR_ACCESS_DENIED |
jz @f |
mov al, 0 |
@@: |
xor ebx, ebx |
ret |
.exists_file: |
; found file; if we are creating directory, return "access denied", |
; if we are creating file, delete existing file and continue |
cmp byte [esp+20+28], 0 |
jz @f |
add esp, 20 |
popad |
mov eax, ERROR_ACCESS_DENIED |
xor ebx, ebx |
ret |
@@: |
; delete FAT chain |
push edi |
xor eax, eax |
mov dword [edi+28], eax ; zero size |
xchg ax, word [edi+26] ; start cluster |
test eax, eax |
jz .done1 |
@@: |
cmp eax, 0xFF8 |
jae .done1 |
lea edi, [RAMDISK_FAT + eax*2] ; position in FAT |
xor eax, eax |
xchg ax, [edi] |
jmp @b |
.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 |
jmp .doit |
.notfound: |
; file is not found; generate short name |
call fat_name_is_legal |
jc @f |
add esp, 20 |
popad |
mov eax, ERROR_FILE_NOT_FOUND |
xor ebx, ebx |
ret |
@@: |
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 [eax], ebp |
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 |
jmp .found |
.short_name_found: |
pop ecx edi esi |
call fat_next_short_name |
jnc .test_short_name_loop |
.disk_full: |
add esp, 12+20 |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.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 |
push 1 |
pop eax ; 1 entry |
jnz .notilde |
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total |
xor eax, eax |
@@: |
cmp byte [esi], 0 |
jz @f |
inc esi |
inc eax |
jmp @b |
@@: |
sub esi, eax |
add eax, 12+13 |
mov ecx, 13 |
push edx |
cdq |
div ecx |
pop edx |
.notilde: |
push -1 |
push -1 |
; find <eax> successive entries in directory |
xor ecx, ecx |
push eax |
lea eax, [esp+12+8+12+8] |
mov [eax], ebp |
call dword [eax-4] |
pop eax |
.scan_dir: |
cmp byte [edi], 0 |
jz .free |
cmp byte [edi], 0xE5 |
jz .free |
xor ecx, ecx |
.scan_cont: |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax-8] |
pop eax |
jnc .scan_dir |
push eax |
lea eax, [esp+12+8+12+8] |
call dword [eax+8] ; extend directory |
pop eax |
jnc .scan_dir |
add esp, 8+8+12+20 |
popad |
mov eax, ERROR_DISK_FULL |
xor ebx, ebx |
ret |
.free: |
test ecx, ecx |
jnz @f |
mov [esp], edi |
mov ecx, [esp+8+8+12+8] |
mov [esp+4], ecx |
xor ecx, ecx |
@@: |
inc ecx |
cmp ecx, eax |
jb .scan_cont |
; found! |
; calculate name checksum |
push esi ecx |
mov esi, [esp+8+8] |
mov ecx, 11 |
xor eax, eax |
@@: |
ror al, 1 |
add al, [esi] |
inc esi |
loop @b |
pop ecx esi |
pop edi |
pop dword [esp+8+12+8] |
; edi points to last entry in free chunk |
dec ecx |
jz .nolfn |
push esi |
push eax |
mov al, 40h |
.writelfn: |
or al, cl |
mov esi, [esp+4] |
push ecx |
dec ecx |
imul ecx, 13 |
add esi, ecx |
stosb |
mov cl, 5 |
call .read_symbols |
mov ax, 0xF |
stosw |
mov al, [esp+4] |
stosb |
mov cl, 6 |
call .read_symbols |
xor eax, eax |
stosw |
mov cl, 2 |
call .read_symbols |
pop ecx |
lea eax, [esp+8+8+12+8] |
call dword [eax+4] ; next write |
xor eax, eax |
loop .writelfn |
pop eax |
pop esi |
.nolfn: |
xchg esi, [esp] |
mov ecx, 11 |
rep movsb |
mov word [edi], 20h ; attributes |
sub edi, 11 |
pop esi ecx |
add esp, 12 |
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 |
and word [edi+20], 0 ; high word of cluster |
and word [edi+26], 0 ; low word of cluster - to be filled |
and dword [edi+28], 0 ; file size - to be filled |
cmp byte [esp+20+28], 0 |
jz .doit |
; create directory |
mov byte [edi+11], 10h ; attributes: folder |
mov ecx, 32*2 |
mov edx, edi |
.doit: |
push edx |
push ecx |
push edi |
add edi, 26 ; edi points to low word of cluster |
push edi |
jecxz .done |
mov ecx, 2849 |
mov edi, RAMDISK_FAT |
.write_loop: |
; allocate new cluster |
xor eax, eax |
repnz scasw |
jnz .disk_full2 |
dec edi |
dec edi |
; lea eax, [edi-(RAMDISK_FAT)] |
mov eax, edi |
sub eax, RAMDISK_FAT |
shr eax, 1 ; eax = cluster |
mov word [edi], 0xFFF ; mark as last cluster |
xchg edi, [esp] |
stosw |
pop edi |
push edi |
inc ecx |
; write data |
cmp byte [esp+16+20+28], 0 |
jnz .writedir |
shl eax, 9 |
add eax, RAMDISK+31*512 |
.writefile: |
mov ebx, edx |
xchg eax, ebx |
push ecx |
mov ecx, 512 |
cmp dword [esp+12], ecx |
jae @f |
mov ecx, [esp+12] |
@@: |
call memmove |
add edx, ecx |
sub [esp+12], ecx |
pop ecx |
jnz .write_loop |
.done: |
mov ebx, edx |
pop edi edi ecx edx |
sub ebx, edx |
mov [edi+28], ebx |
add esp, 20 |
mov [esp+16], ebx |
popad |
xor eax, eax |
ret |
.disk_full2: |
mov ebx, edx |
pop edi edi ecx edx |
sub ebx, edx |
mov [edi+28], ebx |
add esp, 20 |
mov [esp+16], ebx |
popad |
push ERROR_DISK_FULL |
pop eax |
ret |
.writedir: |
mov edi, eax |
shl edi, 9 |
add edi, RAMDISK+31*512 |
mov esi, edx |
mov ecx, 32/4 |
push ecx |
rep movsd |
mov dword [edi-32], '. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov word [edi-32+26], ax |
mov esi, edx |
pop ecx |
rep movsd |
mov dword [edi-32], '.. ' |
mov dword [edi-32+4], ' ' |
mov dword [edi-32+8], ' ' |
mov byte [edi-32+11], 10h |
mov eax, [esp+16+8] |
mov word [edi-32+26], ax |
xor eax, eax |
mov ecx, (512-32*2)/4 |
rep stosd |
pop edi edi ecx edx |
add esp, 20 |
popad |
xor eax, eax |
xor ebx, ebx |
ret |
.read_symbol: |
or ax, -1 |
test esi, esi |
jz .retFFFF |
lodsb |
test al, al |
jnz ansi2uni_char |
xor eax, eax |
xor esi, esi |
.retFFFF: |
ret |
.read_symbols: |
call .read_symbol |
stosw |
loop .read_symbols |
ret |
;---------------------------------------------------------------- |
; |
; fs_RamdiskWrite - LFN variant for writing to sys floppy |
; |
; esi points to filename |
; ebx pointer to 64-bit number = first wanted byte, 0+ |
; may be ebx=0 - start from first byte |
; ecx number of bytes to write, 0+ |
; edx mem location to data |
; |
; ret ebx = bytes written (maybe 0) |
; eax = 0 ok write or other = errormsg |
; |
;-------------------------------------------------------------- |
@@: |
push ERROR_ACCESS_DENIED |
fs_RamdiskWrite.ret0: |
pop eax |
xor ebx, ebx |
ret |
fs_RamdiskWrite: |
cmp byte [esi], 0 |
jz @b |
pushad |
call rd_find_lfn |
jnc .found |
popad |
push ERROR_FILE_NOT_FOUND |
jmp .ret0 |
.found: |
; must not be directory |
test byte [edi+11], 10h |
jz @f |
popad |
push ERROR_ACCESS_DENIED |
jmp .ret0 |
@@: |
; FAT does not support files larger than 4GB |
test ebx, ebx |
jz .l1 |
cmp dword [ebx+4], 0 |
jz @f |
.eof: |
popad |
push ERROR_END_OF_FILE |
jmp .ret0 |
@@: |
mov ebx, [ebx] |
.l1: |
; now edi points to direntry, ebx=start byte to write, |
; ecx=number of bytes to write, edx=data pointer |
call fat_update_datetime |
; extend file if needed |
add ecx, ebx |
jc .eof ; FAT does not support files larger than 4GB |
push 0 ; return value=0 |
cmp ecx, [edi+28] |
jbe .length_ok |
cmp ecx, ebx |
jz .length_ok |
call ramdisk_extend_file |
jnc .length_ok |
; ramdisk_extend_file can return two error codes: FAT table error or disk full. |
; First case is fatal error, in second case we may write some data |
mov [esp], eax |
cmp al, ERROR_DISK_FULL |
jz .disk_full |
pop eax |
mov [esp+28], eax |
popad |
xor ebx, ebx |
ret |
.disk_full: |
; correct number of bytes to write |
mov ecx, [edi+28] |
cmp ecx, ebx |
ja .length_ok |
.ret: |
pop eax |
mov [esp+28], eax ; eax=return value |
sub edx, [esp+20] |
mov [esp+16], edx ; ebx=number of written bytes |
popad |
ret |
.length_ok: |
; now ebx=start pos, ecx=end pos, both lie inside file |
sub ecx, ebx |
jz .ret |
movzx edi, word [edi+26] ; starting cluster |
.write_loop: |
sub ebx, 0x200 |
jae .next_cluster |
push ecx |
neg ebx |
cmp ecx, ebx |
jbe @f |
mov ecx, ebx |
@@: |
mov eax, edi |
shl eax, 9 |
add eax, RAMDISK+31*512+0x200 |
sub eax, ebx |
mov ebx, eax |
mov eax, edx |
call memmove |
xor ebx, ebx |
add edx, ecx |
sub [esp], ecx |
pop ecx |
jz .ret |
.next_cluster: |
movzx edi, word [edi*2+RAMDISK_FAT] |
jmp .write_loop |
ramdisk_extend_file.zero_size: |
xor eax, eax |
jmp ramdisk_extend_file.start_extend |
; extends file on ramdisk to given size, new data area is filled by 0 |
; in: edi->direntry, ecx=new size |
; out: CF=0 => OK, eax=0 |
; CF=1 => error, eax=code (ERROR_FAT_TABLE or ERROR_DISK_FULL) |
ramdisk_extend_file: |
push ecx |
; find the last cluster of file |
movzx eax, word [edi+26] ; first cluster |
mov ecx, [edi+28] |
jecxz .zero_size |
@@: |
sub ecx, 0x200 |
jbe @f |
mov eax, [eax*2+RAMDISK_FAT] |
and eax, 0xFFF |
jz .fat_err |
cmp eax, 0xFF8 |
jb @b |
.fat_err: |
pop ecx |
push ERROR_FAT_TABLE |
pop eax |
stc |
ret |
@@: |
push eax |
mov eax, [eax*2+RAMDISK_FAT] |
and eax, 0xFFF |
cmp eax, 0xFF8 |
pop eax |
jb .fat_err |
; set length to full number of sectors and make sure that last sector is zero-padded |
sub [edi+28], ecx |
push eax edi |
mov edi, eax |
shl edi, 9 |
lea edi, [edi+RAMDISK+31*512+0x200+ecx] |
neg ecx |
xor eax, eax |
rep stosb |
pop edi eax |
.start_extend: |
pop ecx |
; now do extend |
push edx esi |
mov esi, RAMDISK_FAT+2*2 ; start scan from cluster 2 |
mov edx, 2847 ; number of clusters to scan |
.extend_loop: |
cmp [edi+28], ecx |
jae .extend_done |
; add new sector |
push ecx |
mov ecx, edx |
push edi |
mov edi, esi |
jecxz .disk_full |
push eax |
xor eax, eax |
repnz scasw |
pop eax |
jnz .disk_full |
mov word [edi-2], 0xFFF |
mov esi, edi |
mov edx, ecx |
sub edi, RAMDISK_FAT |
shr edi, 1 |
dec edi ; now edi=new cluster |
test eax, eax |
jz .first_cluster |
mov [RAMDISK_FAT+eax*2], di |
jmp @f |
.first_cluster: |
pop eax ; eax->direntry |
push eax |
mov [eax+26], di |
@@: |
push edi |
shl edi, 9 |
add edi, RAMDISK+31*512 |
xor eax, eax |
mov ecx, 512/4 |
rep stosd |
pop eax ; eax=new cluster |
pop edi ; edi->direntry |
pop ecx ; ecx=required size |
add dword [edi+28], 0x200 |
jmp .extend_loop |
.extend_done: |
mov [edi+28], ecx |
pop esi edx |
xor eax, eax ; CF=0 |
ret |
.disk_full: |
pop edi ecx |
pop esi edx |
stc |
push ERROR_DISK_FULL |
pop eax |
ret |
fat_update_datetime: |
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 |
ret |
;---------------------------------------------------------------- |
; |
; fs_RamdiskSetFileEnd - set end of file on ramdisk |
; |
; esi points to filename |
; ebx points to 64-bit number = new file size |
; ecx ignored (reserved) |
; edx ignored (reserved) |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_RamdiskSetFileEnd: |
cmp byte [esi], 0 |
jnz @f |
.access_denied: |
push ERROR_ACCESS_DENIED |
jmp .ret |
@@: |
push edi |
call rd_find_lfn |
jnc @f |
pop edi |
push ERROR_FILE_NOT_FOUND |
.ret: |
pop eax |
ret |
@@: |
; must not be directory |
test byte [edi+11], 10h |
jz @f |
pop edi |
jmp .access_denied |
@@: |
; file size must not exceed 4Gb |
cmp dword [ebx+4], 0 |
jz @f |
pop edi |
push ERROR_END_OF_FILE |
jmp .ret |
@@: |
; set file modification date/time to current |
call fat_update_datetime |
mov eax, [ebx] |
cmp eax, [edi+28] |
jb .truncate |
ja .expand |
pop edi |
xor eax, eax |
ret |
.expand: |
push ecx |
mov ecx, eax |
call ramdisk_extend_file |
pop ecx |
pop edi |
ret |
.truncate: |
mov [edi+28], eax |
push ecx |
movzx ecx, word [edi+26] |
test eax, eax |
jz .zero_size |
; find new last sector |
@@: |
sub eax, 0x200 |
jbe @f |
movzx ecx, word [RAMDISK_FAT+ecx*2] |
jmp @b |
@@: |
; zero data at the end of last sector |
push ecx |
mov edi, ecx |
shl edi, 9 |
lea edi, [edi+RAMDISK+31*512+eax+0x200] |
mov ecx, eax |
neg ecx |
xor eax, eax |
rep stosb |
pop ecx |
; terminate FAT chain |
lea ecx, [RAMDISK_FAT+ecx+ecx] |
push dword [ecx] |
mov word [ecx], 0xFFF |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.zero_size: |
and word [edi+26], 0 |
.delete: |
; delete FAT chain starting with ecx |
; mark all clusters as free |
cmp ecx, 0xFF8 |
jae .deleted |
lea ecx, [RAMDISK_FAT+ecx+ecx] |
push dword [ecx] |
and word [ecx], 0 |
pop ecx |
and ecx, 0xFFF |
jmp .delete |
.deleted: |
pop ecx |
pop edi |
xor eax, eax |
ret |
fs_RamdiskGetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call rd_find_lfn |
fs_GetFileInfo_finish: |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
push esi ebp |
xor ebp, ebp |
mov esi, edx |
and dword [esi+4], 0 |
call fat_entry_to_bdfe2 |
pop ebp esi |
pop edi |
xor eax, eax |
ret |
fs_RamdiskSetFileInfo: |
cmp byte [esi], 0 |
jnz @f |
mov eax, 2 ; unsupported |
ret |
@@: |
push edi |
call rd_find_lfn |
jnc @f |
pop edi |
mov eax, ERROR_FILE_NOT_FOUND |
ret |
@@: |
call bdfe_to_fat_entry |
pop edi |
xor eax, eax |
ret |
;---------------------------------------------------------------- |
; |
; fs_RamdiskDelete - delete file or empty folder from ramdisk |
; |
; esi points to filename |
; |
; ret eax = 0 ok or other = errormsg |
; |
;-------------------------------------------------------------- |
fs_RamdiskDelete: |
cmp byte [esi], 0 |
jnz @f |
; cannot delete root! |
.access_denied: |
push ERROR_ACCESS_DENIED |
.pop_ret: |
pop eax |
ret |
@@: |
and [rd_prev_sector], 0 |
and [rd_prev_prev_sector], 0 |
push edi |
call rd_find_lfn |
jnc .found |
pop edi |
push ERROR_FILE_NOT_FOUND |
jmp .pop_ret |
.found: |
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! |
movzx eax, word [edi+26] |
push ebx |
mov ebx, eax |
shl ebx, 9 |
add ebx, RAMDISK + 31*0x200 + 2*0x20 |
.checkempty: |
cmp byte [ebx], 0 |
jz .empty |
cmp byte [ebx], 0xE5 |
jnz .notempty |
add ebx, 0x20 |
test ebx, 0x1FF |
jnz .checkempty |
movzx eax, word [RAMDISK_FAT + eax*2] |
test eax, eax |
jz .empty |
mov ebx, eax |
shl ebx, 9 |
add ebx, RAMDISK + 31*0x200 |
jmp .checkempty |
.notempty: |
pop ebx |
.access_denied2: |
pop edi |
jmp .access_denied |
.empty: |
pop ebx |
.dodel: |
movzx eax, word [edi+26] |
; delete folder entry |
mov byte [edi], 0xE5 |
; delete LFN (if present) |
.lfndel: |
test edi, 0x1FF |
jnz @f |
cmp [rd_prev_sector], 0 |
jz @f |
cmp [rd_prev_sector], -1 |
jz .lfndone |
mov edi, [rd_prev_sector] |
push [rd_prev_prev_sector] |
pop [rd_prev_sector] |
or [rd_prev_prev_sector], -1 |
shl edi, 9 |
add edi, RAMDISK + 31*0x200 + 0x200 |
@@: |
sub edi, 0x20 |
cmp byte [edi], 0xE5 |
jz .lfndone |
cmp byte [edi+11], 0xF |
jnz .lfndone |
mov byte [edi], 0xE5 |
jmp .lfndel |
.lfndone: |
; delete FAT chain |
test eax, eax |
jz .done |
lea eax, [RAMDISK_FAT + eax*2] |
push dword [eax] |
and word [eax], 0 |
pop eax |
and eax, 0xFFF |
jmp .lfndone |
.done: |
pop edi |
xor eax, eax |
ret |
; \end{diamond} |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/blkdev |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/boot/bootcode.inc |
---|
0,0 → 1,1384 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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: |
; 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 |
} |
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, 3000h |
mov ss, ax |
mov sp, 0EC00h |
; 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 |
; \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 |
@@: |
; \end{diamond}[02.12.2005] |
; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source hard disk |
; (see comment to bx_from_load) |
cmp cx, 'HA' |
jnz no_hd_load |
cmp dx, 'RD' |
jnz no_hd_load |
mov word [cs:bx_from_load], bx ; {SPraid}[13.03.2007] |
no_hd_load: |
; set up stack |
mov ax, 3000h |
mov ss, ax |
mov sp, 0EC00h |
; 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 |
sti |
; set up esp |
movzx esp, sp |
push 0 |
pop es |
and word [es:BOOT_IDE_BASE_ADDR], 0 |
; \begin{Mario79} |
; find HDD IDE DMA PCI device |
; check for PCI BIOS |
mov ax, 0xB101 |
int 0x1A |
jc .nopci |
cmp edx, 'PCI ' |
jnz .nopci |
; find PCI class code |
; class 1 = mass storage |
; subclass 1 = IDE controller |
; a) class 1, subclass 1, programming interface 0x80 |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x80 |
xor si, si ; device index = 0 |
int 0x1A |
jnc .found |
; b) class 1, subclass 1, programming interface 0x8A |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x8A |
xor si, si ; device index = 0 |
int 0x1A |
jnc .found |
; c) class 1, subclass 1, programming interface 0x85 |
mov ax, 0xB103 |
mov ecx, 1*10000h + 1*100h + 0x85 |
xor si, si |
int 0x1A |
jc .nopci |
.found: |
; get memory base |
mov ax, 0xB10A |
mov di, 0x20 ; memory base is config register at 0x20 |
int 0x1A |
jc .nopci |
and cx, 0xFFF0 ; clear address decode type |
mov [es:BOOT_IDE_BASE_ADDR], cx |
.nopci: |
; \end{Mario79} |
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 |
;;;/diamond today 5.02.2008 |
; 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 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; --------------- APM --------------------- |
and word [es:BOOT_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_APM_VERSION], ax ; Save APM Version |
mov [es:BOOT_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_APM_ENTRY], ebx |
mov [es:BOOT_APM_CODE_32], ax |
mov [es:BOOT_APM_CODE_16], cx |
mov [es:BOOT_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_dma = use DMA access? |
; c) preboot_vrrm = use VRR? |
; d) preboot_device = from what 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_biosdisk-preboot_device], 1 |
adc byte [di+preboot_biosdisk-preboot_device], 0 |
;; default value for VRR is OFF |
; cmp byte [di+preboot_vrrm-preboot_device], 0 |
; jnz @f |
; mov byte [di+preboot_vrrm-preboot_device], 2 |
;@@: |
; notify user |
_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, vrrm_msg |
; cmp [preboot_vrrm], 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' |
jz .change_a |
cmp al, 'b' |
jz .change_b |
; cmp al, 'c' |
; jz .change_c |
cmp al, 'c' ; 'd' |
jnz .show_remarks |
_setcursor 15,0 |
mov si, bdev |
call print |
if defined extended_primary_loader |
mov bx, '12' |
else |
mov bx, '14' |
end if |
call getkey |
mov [preboot_device], al |
_setcursor 13,0 |
.d: |
if ~ defined extended_primary_loader |
mov [.bSettingsChanged], 1 |
end if |
call clear_vmodes_table ;clear vmodes_table |
jmp .printcfg |
.change_a: |
.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 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: |
_setcursor 15,0 |
; mov si, ask_dma |
; call print |
; mov bx, '13' |
; call getkey |
; mov [preboot_dma], al |
mov si, ask_bd |
call print |
mov bx, '12' |
call getkey |
mov [preboot_biosdisk], al |
_setcursor 11,0 |
jmp .d |
;.change_c: |
; _setcursor 15,0 |
; mov si, vrrmprint |
; call print |
; mov bx, '12' |
; call getkey |
; mov [preboot_vrrm], al |
; _setcursor 12,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 |
sub ax, 18*5 |
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, 'ã' |
jz @f |
mov cl, 'ë' |
@@: |
mov [time_str+9], cl |
else if lang eq et |
cmp al, 1 |
ja @f |
mov [time_str+9], ' ' |
mov [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 15,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 |
cmp al, 'y' |
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 15,0 |
call printplain |
_setcursor 15,0 |
.load: |
end if |
; \end{diamond}[02.12.2005] |
; ASK GRAPHICS MODE |
call set_vmode |
; GRAPHICS ACCELERATION |
; force yes |
mov [es:BOOT_MTRR], byte 1 |
; DMA ACCESS TO HD |
mov al, [preboot_dma] |
mov [es:BOOT_DMA], al |
;; VRR_M USE |
; |
; mov al,[preboot_vrrm] |
; mov [es:0x9030], al |
; BOOT DEVICE |
mov al, [preboot_device] |
dec al |
mov [boot_dev], al |
; GET MEMORY MAP |
include '../detect/biosmem.inc' |
; READ DISKETTE TO MEMORY |
cmp [boot_dev], 0 |
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 [boot_dev], 1 |
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_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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/booten.inc |
---|
0,0 → 1,101 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
$Revision: 2455 $ |
d80x25_bottom: |
db 186,' KolibriOS is based on MenuetOS and comes with ABSOLUTELY ' |
db 'NO WARRANTY ',186 |
db 186,' See file COPYING for details ' |
db ' ',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]: ",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 [abcd] to change settings, press [Enter] to continue booting",13,10,0 |
time_msg db " or wait " |
time_str db " 5 seconds" |
db " before automatical continuation",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 |
preboot_device_msg db " [c] Floppy image: ",0 |
if defined extended_primary_loader |
preboot_device_msgs dw 0,pdm1,pdm2,0 |
pdm1 db "real floppy",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
else |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
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 db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 colors ³ ³',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 colors ³ ³',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ',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 the item [b].",0 |
remarks dw remark1, remark2 |
num_remarks = 2 |
/kernel/branches/net/boot/bootet.inc |
---|
0,0 → 1,101 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
$Revision$ |
d80x25_bottom: |
db 186,' KolibriOS pohineb MenuetOS ja kaasas IGASUGUSE GARANTI' |
db 'ITA ',186 |
db 186,' Naha faili COPYING detailid ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
msg_apm db " APM x.x ", 0 |
novesa db "Ekraan: EGA/CGA",13,10,0 |
s_vesa db "Vesa versioon: " |
.ver db "?.?",13,10,0 |
gr_mode db "Vali videomode: ",13,10,0 |
ask_bd db "Lisa kettad nahtavaks BIOS reziim V86? [1-jah, 2-no]: ",0 |
if defined extended_primary_loader |
bdev db "Paigalda mäluketas [1-diskett; 2-kolibri.img]: ",0 |
else |
bdev db "Paigalda mäluketas [1-diskett; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-kasuta eellaaditud mäluketast kerneli restardist;" |
db 13,10,186," " |
db "4-loo tühi pilt]: ",0 |
end if |
prnotfnd db "Fataalne - Videoreziimi ei leitud.",0 |
not386 db "Fataalne - CPU 386+ on vajalik.",0 |
fatalsel db "Fataalne - Graafilist reziimi riistvara ei toeta.",0 |
pres_key db "Vajutage suvalist klahvi, et valida uus videomode.",0 |
badsect db 13,10,186," Fataalne - Vigane sektor. Asenda diskett.",0 |
memmovefailed db 13,10,186," Fataalne - Int 0x15 liigutamine ebaõnnestus.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db "Loen disketti: 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 "Vajuta [abcd] seadete muutmiseks, vajuta [Enter] laadimise jätkamiseks",13,10,0 |
time_msg db " või oota " |
time_str db " 5 sekundit" |
db " automaatseks jätkamiseks",13,10,0 |
current_cfg_msg db "Praegused seaded:",13,10,0 |
curvideo_msg db " [a] Videoreziim: ",0 |
mode0 db "320x200, EGA/CGA 256 värvi",0 |
mode9 db "640x480, VGA 16 värvi",0 |
usebd_msg db " [b] Lisa kettad nahtavaks BIOS:",0 |
on_msg db " sees",13,10,0 |
off_msg db " väljas",13,10,0 |
preboot_device_msg db " [c] Disketi kujutis: ",0 |
if defined extended_primary_loader |
preboot_device_msgs dw 0,pdm1,pdm2,0 |
pdm1 db "reaalne diskett",13,10,0 |
pdm2 db "kolibri.img",13,10,0 |
else |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
pdm1 db "reaalne diskett",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "kasuta juba laaditud kujutist",13,10,0 |
pdm4 db "loo tühi pilt",13,10,0 |
end if |
loading_msg db "Laadin KolibriOS...",0 |
if ~ defined extended_primary_loader |
save_quest db "Jäta meelde praegused seaded? [y/n]: ",0 |
loader_block_error db "Alglaaduri andmed vigased, ei saa jätkata. Peatatud.",0 |
end if |
_st db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 colors ³ ³',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 colors ³ ³',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ',13,10,0 |
remark1 db "Vaikimisi maaratud vaartused on valitud mugavuse enamikes, kuid mitte koik.",0 |
remark2 db "Kui susteem ei kaivitu, proovige lulitada kirje [b].",0 |
remarks dw remark1, remark2 |
num_remarks = 2 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/bootge.inc |
---|
0,0 → 1,101 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;====================================================================== |
; |
; BOOT DATA |
; |
;====================================================================== |
$Revision$ |
d80x25_bottom: |
db 186,' KolibriOS basiert auf MenuetOS und wird ohne jegliche ' |
db ' Garantie vertrieben ',186 |
db 186,' Details stehen in der Datei COPYING ' |
db ' ',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 [abcd], 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 |
preboot_device_msg db " [c] 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 |
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 db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 colors ³ ³',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 colors ³ ³',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ',13,10,0 |
remark1 db "Die Standardwerte sind fur die meisten gewahlt, aber nicht fur jedermann.",0 |
remark2 db "Wenn das System nicht bootet, versuchen, das Element [b] deaktivieren.",0 |
remarks dw remark1, remark2 |
num_remarks = 2 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/bootru.inc |
---|
0,0 → 1,101 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;================================================================= |
; |
; BOOT DATA |
; |
;================================================================= |
$Revision$ |
d80x25_bottom: |
db 186,' KolibriOS ®á®¢ MenuetOS ¨ ' |
db ' A. ',186 |
db 186,' ®¤à®¡¥¥ ᬮâà¨â¥ ¢ ä ©«¥ COPYING.TXT ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
msg_apm db " APM x.x ", 0 |
novesa db "¨¤¥®ª àâ : EGA/CGA",13,10,0 |
s_vesa db "¥àá¨ï VESA: " |
.ver db "?.?",13,10,0 |
gr_mode db "ë¡¥à¨â¥ ¢¨¤¥®à¥¦¨¬: ",13,10,0 |
ask_bd db "®¡ ¢¨âì ¤¨áª¨, ¢¨¤¨¬ë¥ ç¥à¥§ BIOS ¢ ०¨¬¥ V86? [1-¤ , 2-¥â]: ",0 |
if defined extended_primary_loader |
bdev db " £à㧨âì ®¡à § ¨§ [1-¤¨áª¥â ; 2-kolibri.img ¨§ ¯ ¯ª¨ § £à㧪¨]: ",0 |
else |
bdev db " £à㧨âì ®¡à § ¨§ [1-¤¨áª¥â ; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-¨á¯®«ì§®¢ âì 㦥 § £àã¦¥ë© ®¡à §;" |
db 13,10,186," " |
db "4-ᮧ¤ âì ç¨áâë© ®¡à §]: ",0 |
end if |
prnotfnd db "訡ª - ¨¤¥®à¥¦¨¬ ¥ ©¤¥.",0 |
not386 db "訡ª - ॡã¥âáï ¯à®æ¥áá®à 386+.",0 |
fatalsel db "訡ª - ë¡à ë© ¢¨¤¥®à¥¦¨¬ ¥ ¯®¤¤¥à¦¨¢ ¥âáï.",0 |
pres_key db " ¦¨¬¨â¥ «î¡ãî ª« ¢¨èã, ¤«ï ¯¥à¥å®¤ ¢ ¢ë¡®à ०¨¬®¢.",0 |
badsect db 13,10,186," 訡ª - ¨áª¥â ¯®¢à¥¦¤¥ . ®¯à®¡ã©â¥ ¤àã£ãî.",0 |
memmovefailed db 13,10,186," 訡ª - Int 0x15 move failed.",0 |
okt db " ... OK" |
linef db 13,10,0 |
diskload db " £à㧪 ¤¨áª¥âë: 00 %",8,8,8,8,0 |
pros db "00" |
backspace2 db 8,8,0 |
boot_dev db 0 |
start_msg db " ¦¬¨â¥ [abcd] ¤«ï ¨§¬¥¥¨ï áâ஥ª, [Enter] ¤«ï ¯à®¤®«¦¥¨ï § £à㧪¨",13,10,0 |
time_msg db " ¨«¨ ¯®¤®¦¤¨â¥ " |
time_str db " 5 ᥪ㭤 " |
db " ¤® ¢â®¬ â¨ç¥áª®£® ¯à®¤®«¦¥¨ï",13,10,0 |
current_cfg_msg db "¥ªã騥 áâனª¨:",13,10,0 |
curvideo_msg db " [a] ¨¤¥®à¥¦¨¬: ",0 |
mode0 db "320x200, EGA/CGA 256 梥⮢",13,10,0 |
mode9 db "640x480, VGA 16 梥⮢",13,10,0 |
usebd_msg db " [b] ®¡ ¢¨âì ¤¨áª¨, ¢¨¤¨¬ë¥ ç¥à¥§ BIOS:",0 |
on_msg db " ¢ª«",13,10,0 |
off_msg db " ¢ëª«",13,10,0 |
preboot_device_msg db " [c] ¡à § ¤¨áª¥âë: ",0 |
if defined extended_primary_loader |
preboot_device_msgs dw 0,pdm1,pdm2,0 |
pdm1 db " áâ®ïé ï ¤¨áª¥â ",13,10,0 |
pdm2 db "kolibri.img ¨§ ¯ ¯ª¨ § £à㧪¨",13,10,0 |
else |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4 |
pdm1 db " áâ®ïé ï ¤¨áª¥â ",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "¨á¯®«ì§®¢ âì 㦥 § £àã¦¥ë© ®¡à §",13,10,0 |
pdm4 db "ᮧ¤ âì ç¨áâë© ®¡à §",13,10,0 |
end if |
loading_msg db "¤ñâ § £à㧪 KolibriOS...",0 |
if ~ defined extended_primary_loader ; saving not supported in this case |
save_quest db " ¯®¬¨âì ⥪ã騥 áâனª¨? [y/n]: ",0 |
loader_block_error db "訡ª ¢ ¤ ëå ç «ì®£® § £àã§ç¨ª , ¯à®¤®«¦¥¨¥ ¥¢®§¬®¦®.",0 |
end if |
_st db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿ ',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 梥⮢ ³ ³ ',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 梥⮢ ³ ³ ',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³ ',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ ',13,10,0 |
remark1 db " ç¥¨ï ¯® 㬮«ç ¨î ¢ë¡à ë ¤«ï 㤮¡á⢠¡®«ìè¨á⢠, ® ¥ ¢á¥å.",0 |
remark2 db " ᫨ ã á ¥ £à㧨âáï á¨á⥬ , ¯®¯à®¡ã©â¥ ®âª«îç¨âì ¯ãªâ [b].",0 |
remarks dw remark1, remark2 |
num_remarks = 2 |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/bootsp.inc |
---|
0,0 → 1,103 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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: 2455 $ |
d80x25_bottom: |
db 186,' KolibriOS est basado en MenuetOS y viene ABSOLUTAMENTE ' |
db 'SIN GARANT¡A ',186 |
db 186,' Lee el archivo COPYING por m s detalles ' |
db ' ',186 |
line_full_bottom |
d80x25_bottom_num = 3 |
msg_apm db " APM x.x ", 0 |
novesa db "Monitor: EGA/CGA",13,10,0 |
s_vesa db "Versi¢n de VESA: " |
.ver db "?.?",13,10,0 |
gr_mode db "Selecciona un modo de video: ",13,10,0 |
ask_bd db "¨Agregar discos visibles por el BIOS emulados en modo V86? [1-si, 2-no]: ",0 |
if defined extended_primary_loader |
bdev db "Cargar unidad ram desde [1-disquete; 2-kolibri.img]: ",0 |
else |
bdev db "Cargar unidad ram desde [1-disquete; 2-C:\kolibri.img (FAT32);" |
db 13,10,186," " |
db "3-usar imagen precargada en el reinicio del n£cleo;" |
db 13,10,186," " |
db "4-crear imagen vac¡a]: ",0 |
end if |
prnotfnd db "Fatal - Modo de video no encontrado.",0 |
not386 db "Fatal - CPU 386+ requerido.",0 |
fatalsel db "Fatal - Modo de gr ficos no soportado por hardware.",0 |
pres_key db "Presiona una tecla para seleccionar otro modo de video.",0 |
badsect db 13,10,186," Fatal - Sector mal. Reemplaze el disquete.",0 |
memmovefailed db 13,10,186," Fatal - Int 0x15 move failed.",0 |
okt db " ... BIEN" |
linef db 13,10,0 |
diskload db "Cargando disquete: 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 "Presiona [abcd] para cambiar la configuraci¢n, [Enter] para continuar",13,10,0 |
time_msg db " o espera " |
time_str db " 5 segundos" |
db " para que inicie autom ticamente",13,10,0 |
current_cfg_msg db "Configuraci¢n actual:",13,10,0 |
curvideo_msg db " [a] Modo de video: ",0 |
mode0 db "320x200, EGA/CGA 256 colores",13,10,0 |
mode9 db "640x480, VGA 16 colores",13,10,0 |
usebd_msg db " [b] Agregar discos visibles por el BIOS:",0 |
on_msg db " activado",13,10,0 |
off_msg db " desactivado",13,10,0 |
preboot_device_msg db " [c] Imagen de disquete: ",0 |
if defined extended_primary_loader |
preboot_device_msgs dw 0,pdm1,pdm2,0 |
pdm1 db "disquete real",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
else |
preboot_device_msgs dw 0,pdm1,pdm2,pdm3 |
pdm1 db "disquete real",13,10,0 |
pdm2 db "C:\kolibri.img (FAT32)",13,10,0 |
pdm3 db "usar imagen ya cargada",13,10,0 |
pdm4 db "crear imagen vac¡a",13,10,0 |
end if |
loading_msg db "Cargando KolibriOS...",0 |
if ~ defined extended_primary_loader |
save_quest db "¨Recordar configuraci¢n actual? [s/n]: ",0 |
loader_block_error db "Bootloader inv lido, no puedo continuar. Detenido.",0 |
end if |
_st db 186,' ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄ¿',13,10,0 |
_r1 db 186,' ³ 320x200 EGA/CGA 256 colores ³ ³',13,10,0 |
_r2 db 186,' ³ 640x480 VGA 16 colores ³ ³',13,10,0 |
_rs db 186,' ³ ????x????@?? SVGA VESA ³ ³',13,10,0 |
_bt db 186,' ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÙ',13,10,0 |
remark1 db "Los valores por defecto puede que no funcionen en algunas configuraciones.",0 |
remark2 db "Si el sistema no inicia, prueba deshabilitar la opci¢n [b].",0 |
remarks dw remark1, remark2 |
num_remarks = 2 |
/kernel/branches/net/boot/bootstr.inc |
---|
0,0 → 1,63 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 = 75 |
store byte ' ' at d80x25_top+cur_line_pos+1 |
rev_var = __REV__ |
while rev_var > 0 |
store byte rev_var mod 10 + '0' at d80x25_top+cur_line_pos |
cur_line_pos = cur_line_pos - 1 |
rev_var = rev_var / 10 |
end while |
store byte ' ' at d80x25_top+cur_line_pos |
store dword ' SVN' at d80x25_top+cur_line_pos-4 |
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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/bootvesa.inc |
---|
0,0 → 1,794 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 ;âðåìåííîå õðàíåíèå êóðñîðà. |
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 equ 9 ;long of visible video table |
size_of_step equ 10 |
scroll_area_size equ (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], 24 ;It show only videomodes to have support 24 and 32 bpp |
jb @f |
; cmp [es:mi.BitsPerPixel],16 |
; jne .l0 |
; cmp [es:mi.GreenMaskSize],5 |
; jne .l0 |
; mov [es:mi.BitsPerPixel],15 |
.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 |
@@: |
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 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 |
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 |
cmp word [es:si+8], 32 |
je .ok |
cmp word [es:si+8], 24 |
je .ok |
.next: |
add si, size_of_step |
cmp word [es:si], -1 |
je .exit |
jmp .loops |
.ok: |
xor ax, ax |
ret |
.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, 70 |
mov bp, 12 |
.loop_start: |
rep stosw |
mov cx, 70 |
add di, 20 |
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_X_RES], ax ; resolution X |
mov word [es:BOOT_Y_RES], bx ; resolution Y |
mov word [es:BOOT_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_LFB], eax |
; ---- vbe voodoo |
BytesPerLine equ 0x10 |
mov ax, [es:di+BytesPerLine] |
mov [es:BOOT_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_BPP], al |
jmp .exit |
.mode0x12_0x13: |
mov byte [es:BOOT_BPP], 32 |
or dword [es:BOOT_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:0x9014], eax |
.exit: |
ret |
;============================================================================= |
;============================================================================= |
;============================================================================= |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/et.inc |
---|
0,0 → 1,16 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
; Full ASCII code font |
; only õ and ä added |
; Kaitz |
ET_FNT: |
fontfile file "ETFONT.FNT" |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/parsers.inc |
---|
0,0 → 1,170 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision: 2288 $ |
; 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_vrr: |
;; vrr is a boolean setting |
; call parse_bool |
; jc .nothing |
;; convert 0 to 2, 1 to 1 |
; inc ax |
; xor al, 3 |
; mov [es:preboot_vrrm], al |
;.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) |
call parse_number |
jc .nothing |
cmp al, 1 |
jb .nothing |
cmp al, 2 |
ja .nothing |
mov [es:preboot_device], al |
.nothing: |
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 |
/kernel/branches/net/boot/preboot.inc |
---|
0,0 → 1,42 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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_vrrm db 0 ; use VRR_M (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 ; boot device |
; (1-floppy 2-harddisk 3-kernel restart 4-format ram disk) |
;!!!! 0 - autodetect !!!! |
preboot_blogesc = 0 ; start immediately after bootlog |
preboot_biosdisk db 0 ; use V86 to access disks through BIOS (1-yes, 2-no) |
if defined extended_primary_loader |
preboot_timeout dw 5*18 ; timeout in 1/18th of second for config settings screen |
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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/rdload.inc |
---|
0,0 → 1,134 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
; READ RAMDISK IMAGE FROM HD |
cmp [boot_dev+OS_BASE+0x10000], 1 |
jne no_sys_on_hd |
test [DRIVE_DATA+1], byte 0x40 |
jz position_2 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x0 |
mov [hdpos], 1 |
mov [fat32part], 0 |
position_1_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+2] |
cmp [fat32part], eax |
jle position_1_1 |
position_2: |
test [DRIVE_DATA+1], byte 0x10 |
jz position_3 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x10 |
mov [hdpos], 2 |
mov [fat32part], 0 |
position_2_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+3] |
cmp eax, [fat32part] |
jle position_2_1 |
position_3: |
test [DRIVE_DATA+1], byte 0x4 |
jz position_4 |
mov [hdbase], 0x170 |
mov [hdid], 0x0 |
mov [hdpos], 3 |
mov [fat32part], 0 |
position_3_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+4] |
cmp eax, [fat32part] |
jle position_3_1 |
position_4: |
test [DRIVE_DATA+1], byte 0x1 |
jz no_sys_on_hd |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
mov [hdpos], 4 |
mov [fat32part], 0 |
position_4_1: |
inc [fat32part] |
call search_and_read_image |
cmp [image_retrieved], 1 |
je yes_sys_on_hd |
movzx eax, byte [DRIVE_DATA+5] |
cmp eax, [fat32part] |
jle position_4_1 |
jmp yes_sys_on_hd |
search_and_read_image: |
call set_FAT32_variables |
mov edx, bootpath |
call read_image |
test eax, eax |
jz image_present |
mov edx, bootpath2 |
call read_image |
test eax, eax |
jz image_present |
ret |
image_present: |
mov [image_retrieved], 1 |
ret |
iglobal |
align 4 |
read_image_fsinfo: |
dd 0 ; function: read |
dq 0 ; offset: zero |
dd 1474560/512 ; size |
dd RAMDISK ; buffer |
db 0 |
dd hdsysimage+OS_BASE+0x10000 |
endg |
read_image: |
mov ebx, read_image_fsinfo |
pushad |
call file_system_lfn_protected |
popad |
ret |
image_retrieved db 0 |
counter_of_partitions db 0 |
no_sys_on_hd: |
; test_to_format_ram_disk (need if not using ram disk) |
cmp [boot_dev+OS_BASE+0x10000], 3 |
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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/ru.inc |
---|
0,0 → 1,102 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/shutdown.inc |
---|
0,0 → 1,212 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 |
pr_mode_exit: |
; setup stack |
mov ax, 0x3000 |
mov ss, ax |
mov esp, 0x0EC00 |
; setup ds |
push cs |
pop ds |
lidt [old_ints_h] |
;remap IRQs |
mov al, 0x11 |
out 0x20, al |
call rdelay |
out 0xA0, al |
call rdelay |
mov al, 0x08 |
out 0x21, al |
call rdelay |
mov al, 0x70 |
out 0xA1, al |
call rdelay |
mov al, 0x04 |
out 0x21, al |
call rdelay |
mov al, 0x02 |
out 0xA1, al |
call rdelay |
mov al, 0x01 |
out 0x21, al |
call rdelay |
out 0xA1, al |
call rdelay |
mov al, 0xB8 |
out 0x21, al |
call rdelay |
mov al, 0xBD |
out 0xA1, al |
sti |
temp_3456: |
xor ax, ax |
mov es, ax |
mov al, byte [es:0x9030] |
cmp al, 1 |
jl nbw |
cmp al, 4 |
jle nbw32 |
nbw: |
in al, 0x60 |
cmp al, 6 |
jae nbw |
mov bl, al |
nbw2: |
in al, 0x60 |
cmp al, bl |
je nbw2 |
cmp al, 240;ax,240 |
jne nbw31 |
mov al, bl |
dec ax |
jmp nbw32 |
nbw31: |
add bl, 128 |
cmp al, bl |
jne nbw |
sub al, 129 |
nbw32: |
dec ax |
dec ax ; 2 = power off |
jnz no_apm_off |
call APM_PowerOff |
jmp $ |
no_apm_off: |
if ~ defined extended_primary_loader ; kernel restarting is not supported |
dec ax ; 3 = reboot |
jnz restart_kernel ; 4 = restart kernel |
end if |
push 0x40 |
pop ds |
mov word[0x0072], 0x1234 |
jmp 0xF000:0xFFF0 |
rdelay: |
ret |
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 |
;!!!!!!!!!!!!!!!!!!!!!!!! |
ret |
if ~ defined extended_primary_loader |
restart_kernel: |
mov ax, 0x0003 ; set text mode for screen |
int 0x10 |
jmp 0x4000:0000 |
restart_kernel_4000: |
cli |
push ds |
pop es |
mov cx, 0x8000 |
push cx |
push 0x7000 |
pop ds |
xor si, si |
xor di, di |
rep movsw |
pop cx |
mov ds, cx |
push 0x2000 |
pop es |
rep movsw |
push 0x9000 |
pop ds |
push 0x3000 |
pop es |
mov cx, 0xE000/2 |
rep movsw |
wbinvd ; write and invalidate cache |
mov al, 00110100b |
out 43h, al |
jcxz $+2 |
mov al, 0xFF |
out 40h, al |
jcxz $+2 |
out 40h, al |
jcxz $+2 |
sti |
; (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) |
in al, 0x60 |
; bootloader interface |
push 0x1000 |
pop ds |
mov si, kernel_restart_bootblock |
mov ax, 'KL' |
jmp 0x1000:0000 |
end if |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/boot/ETFONT.FNT |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mergeinfo |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/kernel/branches/net/boot |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/data32sp.inc |
---|
0,0 → 1,40 |
boot_initirq db 'Inicializar IRQ',0 |
boot_picinit db 'Inicializar PIC',0 |
boot_v86machine db 'Inicializar sistema V86',0 |
boot_inittimer db 'Inicializar reloj del sistema (IRQ0)',0 |
boot_initapic db 'Prueba inicializar APIC',0 |
boot_enableirq db 'Habilitar interrupciones 2, 6, 13, 14, 15',0 |
boot_enablint_ide db 'Habiliar interrupciones en controladores IDE',0 |
boot_detectfloppy db 'Buscar unidades de disquete',0 |
boot_detecthdcd db 'Buscar discos duros y unidades ATAPI',0 |
boot_getcache db 'Tomar memoria para cach',0 |
boot_detectpart db 'Buscar particiones en discos',0 |
boot_init_sys db 'Inicializar directorio del sistema /sys',0 |
boot_loadlibs db 'Cargando librer¡as (.obj)',0 |
boot_memdetect db 'Determinando cantidad de memoria',0 |
boot_tss db 'Configurando TSSs',0 |
boot_cpuid db 'Leyendo CPUIDs',0 |
; boot_devices db 'Detectando dispositivos',0 |
boot_setmouse db 'Configurando el rat¢n',0 |
boot_windefs db 'Setting window defaults',0 |
boot_bgr db 'Calculating background',0 |
boot_resirqports db 'Reservando IRQs y puertos',0 |
boot_setostask db 'Configurando tarea OS',0 |
boot_allirqs db 'Desenmascarando IRQs',0 |
boot_tsc db 'Leyendo TSC',0 |
boot_cpufreq db 'La frequencia del CPU es ',' ',' MHz',0 |
boot_pal_ega db 'Configurando paleta EGA/CGA 320x200',0 |
boot_pal_vga db 'Configurando paleta VGA 640x480',0 |
boot_failed db 'Fallo al iniciar la primer aplicaci¢n',0 |
boot_mtrr db 'Configurando MTRR',0 |
boot_APIC_found db 'APIC habilitado', 0 |
boot_APIC_nfound db 'APIC no encontrado', 0 |
if preboot_blogesc |
boot_tasking db 'Todo configurado - presiona ESC para iniciar',0 |
end if |
msg_version db 'versi¢n incompatible del controlador',13,10,0 |
msg_www db 'por favor, visita www.kolibrios.org',13,10,0 |
ud_user_message db 'Error: instrucci¢n no soportada por el procesador',0 |
/kernel/branches/net/detect/biosdisk.inc |
---|
0,0 → 1,81 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2008-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; Detect all BIOS hard drives. |
; diamond, 2008 |
xor cx, cx |
mov es, cx |
mov di, 0x9080 |
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 |
mov ah, 48h |
push ds |
push es |
pop ds |
mov si, 0xA000 |
mov word [si], 1Eh |
mov ah, 48h |
int 13h |
pop ds |
jc bddc2 |
inc byte [es:0x907F] |
cmp word [es:si], 1Eh |
jb bddl |
cmp word [es:si+1Ah], 0xFFFF |
jz bddl |
mov al, dl |
stosb |
push ds |
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 ds |
jmp bddc2 |
bddl: |
mov al, dl |
stosb |
xor ax, ax |
stosb |
dec ax |
stosw |
; mov al, 0 |
; stosb |
; mov ax, -1 |
; stosw |
bddc2: |
cmp cl, [es:0x475] |
jae bdde |
bddc: |
inc dl |
jnz bdds |
bdde: |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect/biosmem.inc |
---|
0,0 → 1,43 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2009-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; 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, 0x9104 |
mov [di-4], ebx ; no blocks yet |
mov ecx, 20 |
mov edx, 0x534D4150 |
int 15h |
jc no_E820 |
cmp eax, 0x534D4150 |
jnz no_E820 |
e820_mem_loop: |
; cmp byte [di+16], 1 ; ignore non-free areas |
; jnz e820_mem_next |
inc byte [0x9100] |
add di, 20 |
e820_mem_next: |
; consequent calls to fn E820 |
test ebx, ebx |
jz e820_test_done |
cmp byte [0x9100], 32 |
jae 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:mergeinfo |
/kernel/branches/net/detect/sear_par.inc |
---|
0,0 → 1,161 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;**************************************************** |
; ïîèñê ëîãè÷åñêèõ äèñêîâ íà îáíàðóæåííûõ HDD |
; è çàíåñåíèå äàííûõ â îáëàñòü òàáëèöû |
; àâòîð Mario79 |
;**************************************************** |
mov [transfer_adress], DRIVE_DATA+0xa |
search_partitions_ide0: |
test [DRIVE_DATA+1], byte 0x40 |
jz search_partitions_ide1 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x0 |
mov [hdpos], 1 |
mov [known_part], 1 |
search_partitions_ide0_1: |
call set_PARTITION_variables |
test [problem_partition], 2 |
jnz search_partitions_ide1 ; not found part |
test [problem_partition], 1 |
jnz @F ; not found known_part |
;cmp [problem_partition],0 |
;jne search_partitions_ide1 |
inc byte [DRIVE_DATA+2] |
call partition_data_transfer |
add [transfer_adress], 100 |
@@: |
inc [known_part] |
jmp search_partitions_ide0_1 |
search_partitions_ide1: |
test [DRIVE_DATA+1], byte 0x10 |
jz search_partitions_ide2 |
mov [hdbase], 0x1f0 |
mov [hdid], 0x10 |
mov [hdpos], 2 |
mov [known_part], 1 |
search_partitions_ide1_1: |
call set_PARTITION_variables |
test [problem_partition], 2 |
jnz search_partitions_ide2 |
test [problem_partition], 1 |
jnz @F |
;cmp [problem_partition],0 |
;jne search_partitions_ide2 |
inc byte [DRIVE_DATA+3] |
call partition_data_transfer |
add [transfer_adress], 100 |
@@: |
inc [known_part] |
jmp search_partitions_ide1_1 |
search_partitions_ide2: |
test [DRIVE_DATA+1], byte 0x4 |
jz search_partitions_ide3 |
mov [hdbase], 0x170 |
mov [hdid], 0x0 |
mov [hdpos], 3 |
mov [known_part], 1 |
search_partitions_ide2_1: |
call set_PARTITION_variables |
test [problem_partition], 2 |
jnz search_partitions_ide3 |
test [problem_partition], 1 |
jnz @F |
;cmp [problem_partition],0 |
;jne search_partitions_ide3 |
inc byte [DRIVE_DATA+4] |
call partition_data_transfer |
add [transfer_adress], 100 |
@@: |
inc [known_part] |
jmp search_partitions_ide2_1 |
search_partitions_ide3: |
test [DRIVE_DATA+1], byte 0x1 |
jz end_search_partitions_ide |
mov [hdbase], 0x170 |
mov [hdid], 0x10 |
mov [hdpos], 4 |
mov [known_part], 1 |
search_partitions_ide3_1: |
call set_PARTITION_variables |
test [problem_partition], 2 |
jnz end_search_partitions_ide |
test [problem_partition], 1 |
jnz @F |
;cmp [problem_partition],0 |
;jne end_search_partitions_ide |
inc byte [DRIVE_DATA+5] |
call partition_data_transfer |
add [transfer_adress], 100 |
@@: |
inc [known_part] |
jmp search_partitions_ide3_1 |
end_search_partitions_ide: |
mov [hdpos], 80h |
mov ecx, [NumBiosDisks] |
test ecx, ecx |
jz end_search_partitions |
start_search_partitions_bd: |
push ecx |
mov eax, [hdpos] |
and [BiosDiskPartitions+(eax-80h)*4], 0 |
mov [known_part], 1 |
search_partitions_bd: |
call set_PARTITION_variables |
test [problem_partition], 2 |
jnz end_search_partitions_bd |
test [problem_partition], 1 |
jnz @F |
;cmp [problem_partition], 0 |
;jne end_search_partitions_bd |
mov eax, [hdpos] |
inc [BiosDiskPartitions+(eax-80h)*4] |
call partition_data_transfer |
add [transfer_adress], 100 |
@@: |
inc [known_part] |
jmp search_partitions_bd |
end_search_partitions_bd: |
pop ecx |
inc [hdpos] |
loop start_search_partitions_bd |
jmp end_search_partitions |
problem_partition db 0 ; used for partitions search |
include '../fs/part_set.inc' |
partition_data_transfer: |
mov edi, [transfer_adress] |
mov esi, PARTITION_START ;start of file_system_data |
mov ecx, (file_system_data_size+3)/4 |
rep movsd |
ret |
uglobal |
transfer_adress dd 0 |
endg |
partition_data_transfer_1: |
; cli |
push edi |
mov edi, PARTITION_START |
mov esi, [transfer_adress] |
mov ecx, (file_system_data_size+3)/4 |
rep movsd |
pop edi |
; sti |
ret |
end_search_partitions: |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect/dev_fd.inc |
---|
0,0 → 1,37 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;*************************************************** |
; ïðåäâàðèòåëüíàÿ î÷èñòêà îáëàñòè òàáëèöû |
; ïîèñê è çàíåñåíèå â òàáëèöó ïðèâîäîâ FDD |
; àâòîð Mario79 |
;*************************************************** |
xor eax, eax |
mov edi, DRIVE_DATA |
mov ecx, 16384 |
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 |
in al, 0x21 |
and al, 10111111b ; Enable IRQ6 |
out 0x21, al |
@@: |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect/dev_hdcd.inc |
---|
0,0 → 1,394 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
;****************************************************** |
; ïîèñê ïðèâîäîâ HDD è CD |
; àâòîð èñõîäíîãî òåêñòà Êóëàêîâ Âëàäèìèð Ãåííàäüåâè÷. |
; àäàïòàöèÿ è äîðàáîòêà Mario79 |
;****************************************************** |
;**************************************************** |
;* ÏÎÈÑÊ HDD è CD * |
;**************************************************** |
FindHDD: |
mov [ChannelNumber], 1 |
mov [DiskNumber], 0 |
call FindHDD_3 |
; mov ax,[Sector512+176] |
; mov [DRIVE_DATA+6],ax |
; mov ax,[Sector512+126] |
; mov [DRIVE_DATA+8],ax |
; mov ax,[Sector512+128] |
; mov [DRIVE_DATA+8],ax |
mov [DiskNumber], 1 |
call FindHDD_3 |
; mov al,[Sector512+176] |
; mov [DRIVE_DATA+7],al |
inc [ChannelNumber] |
mov [DiskNumber], 0 |
call FindHDD_3 |
; mov al,[Sector512+176] |
; mov [DRIVE_DATA+8],al |
mov [DiskNumber], 1 |
call FindHDD_1 |
; mov al,[Sector512+176] |
; mov [DRIVE_DATA+9],al |
jmp EndFindHDD |
FindHDD_1: |
call ReadHDD_ID |
cmp [DevErrorCode], 0 |
jne FindHDD_2 |
cmp [Sector512+6], word 16 |
ja FindHDD_2 |
cmp [Sector512+12], word 255 |
ja FindHDD_2 |
inc byte [DRIVE_DATA+1] |
jmp FindHDD_2_2 |
FindHDD_2: |
call DeviceReset |
cmp [DevErrorCode], 0 |
jne FindHDD_2_2 |
call ReadCD_ID |
cmp [DevErrorCode], 0 |
jne FindHDD_2_2 |
inc byte [DRIVE_DATA+1] |
inc byte [DRIVE_DATA+1] |
FindHDD_2_2: |
ret |
FindHDD_3: |
call FindHDD_1 |
shl byte [DRIVE_DATA+1], 2 |
ret |
; Àäðåñ ñ÷èòûâàåìîãî ñåêòîðà â ðåæèìå LBA |
uglobal |
SectorAddress DD ? |
endg |
;************************************************* |
;* ×ÒÅÍÈÅ ÈÄÅÍÒÈÔÈÊÀÒÎÐÀ ÆÅÑÒÊÎÃÎ ÄÈÑÊÀ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà (1 èëè 2); * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå (0 èëè 1). * |
;* Èäåíòèôèêàöèîííûé áëîê äàííûõ ñ÷èòûâàåòñÿ * |
;* â ìàññèâ Sector512. * |
;************************************************* |
ReadHDD_ID: |
; Çàäàòü ðåæèì CHS |
mov [ATAAddressMode], 0 |
; Ïîñëàòü êîìàíäó èäåíòèôèêàöèè óñòðîéñòâà |
mov [ATAFeatures], 0 |
mov [ATAHead], 0 |
mov [ATACommand], 0ECh |
call SendCommandToHDD |
cmp [DevErrorCode], 0;ïðîâåðèòü êîä îøèáêè |
jne @@End ;çàêîí÷èòü, ñîõðàíèâ êîä îøèáêè |
mov DX, [ATABasePortAddr] |
add DX, 7 ;àäðåñ ðåãèñòðà ñîñòîÿíè |
mov ecx, 0xffff |
@@WaitCompleet: |
; Ïðîâåðèòü âðåìÿ âûïîëíåíèÿ êîìàíäû |
dec ecx |
; cmp ecx,0 |
jz @@Error1 ;îøèáêà òàéì-àóòà |
; Ïðîâåðèòü ãîòîâíîñòü |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitCompleet |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Error6 |
test AL, 08h ;ñîñòîÿíèå ñèãíàëà DRQ |
jz @@WaitCompleet |
; Ïðèíÿòü áëîê äàííûõ îò êîíòðîëëåðà |
; mov AX,DS |
; mov ES,AX |
mov EDI, Sector512 ;offset Sector512 |
mov DX, [ATABasePortAddr];ðåãèñòð äàííûõ |
mov CX, 256 ;÷èñëî ñ÷èòûâàåìûõ ñëîâ |
rep insw ;ïðèíÿòü áëîê äàííûõ |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Error1: |
mov [DevErrorCode], 1 |
ret |
@@Error6: |
mov [DevErrorCode], 6 |
@@End: |
ret |
iglobal |
; Ñòàíäàðòíûå áàçîâûå àäðåñà êàíàëîâ 1 è 2 |
StandardATABases DW 1F0h, 170h |
endg |
uglobal |
; Íîìåð êàíàëà |
ChannelNumber DW ? |
; Íîìåð äèñêà |
DiskNumber DB ? |
; Áàçîâûé àäðåñ ãðóïïû ïîðòîâ êîíòðîëëåðà ATA |
ATABasePortAddr DW ? |
; Ïàðàìåòðû ATA-êîìàíäû |
ATAFeatures DB ? ;îñîáåííîñòè |
ATASectorCount DB ? ;êîëè÷åñòâî îáðàáàòûâàåìûõ ñåêòîðîâ |
ATASectorNumber DB ? ;íîìåð íà÷àëüíîãî ñåêòîðà |
ATACylinder DW ? ;íîìåð íà÷àëüíîãî öèëèíäðà |
ATAHead DB ? ;íîìåð íà÷àëüíîé ãîëîâêè |
ATAAddressMode DB ? ;ðåæèì àäðåñàöèè (0 - CHS, 1 - LBA) |
ATACommand DB ? ;êîä êîìàíäû, ïîäëåæàùåé âûïîëíåíèþ |
; Êîä îøèáêè (0 - íåò îøèáîê, 1 - ïðåâûøåí äîïóñòèìûé |
; èíòåðâàë îæèäàíèÿ, 2 - íåâåðíûé êîä ðåæèìà àäðåñàöèè, |
; 3 - íåâåðíûé íîìåð êàíàëà, 4 - íåâåðíûé íîìåð äèñêà, |
; 5 - íåâåðíûé íîìåð ãîëîâêè, 6 - îøèáêà ïðè âûïîëíåíèè |
; êîìàíäû) |
DevErrorCode dd ? |
endg |
;**************************************************** |
;* ÏÎÑËÀÒÜ ÊÎÌÀÍÄÓ ÇÀÄÀÍÍÎÌÓ ÄÈÑÊÓ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà (1 èëè 2); * |
;* DiskNumber - íîìåð äèñêà (0 èëè 1); * |
;* ATAFeatures - "îñîáåííîñòè"; * |
;* ATASectorCount - êîëè÷åñòâî ñåêòîðîâ; * |
;* ATASectorNumber - íîìåð íà÷àëüíîãî ñåêòîðà; * |
;* ATACylinder - íîìåð íà÷àëüíîãî öèëèíäðà; * |
;* ATAHead - íîìåð íà÷àëüíîé ãîëîâêè; * |
;* ATAAddressMode - ðåæèì àäðåñàöèè (0-CHS, 1-LBA); * |
;* ATACommand - êîä êîìàíäû. * |
;* Ïîñëå óñïåøíîãî âûïîëíåíèÿ ôóíêöèè: * |
;* â ATABasePortAddr - áàçîâûé àäðåñ HDD; * |
;* â DevErrorCode - íîëü. * |
;* Ïðè âîçíèêíîâåíèè îøèáêè â DevErrorCode áóäåò * |
;* âîçâðàùåí êîä îøèáêè. * |
;**************************************************** |
SendCommandToHDD: |
; Ïðîâåðèòü çíà÷åíèå êîäà ðåæèìà |
cmp [ATAAddressMode], 1 |
ja @@Err2 |
; Ïðîâåðèòü êîððåêòíîñòü íîìåðà êàíàëà |
mov BX, [ChannelNumber] |
cmp BX, 1 |
jb @@Err3 |
cmp BX, 2 |
ja @@Err3 |
; Óñòàíîâèòü áàçîâûé àäðåñ |
dec BX |
shl BX, 1 |
movzx ebx, bx |
mov AX, [ebx+StandardATABases] |
mov [ATABasePortAddr], AX |
; Îæèäàíèå ãîòîâíîñòè HDD ê ïðèåìó êîìàíäû |
; Âûáðàòü íóæíûé äèñê |
mov DX, [ATABasePortAddr] |
add DX, 6 ;àäðåñ ðåãèñòðà ãîëîâîê |
mov AL, [DiskNumber] |
cmp AL, 1 ;ïðîâåðèòü íîìåðà äèñêà |
ja @@Err4 |
shl AL, 4 |
or AL, 10100000b |
out DX, AL |
; Îæèäàòü, ïîêà äèñê íå áóäåò ãîòîâ |
inc DX |
mov ecx, 0xfff |
; mov eax,[timer_ticks] |
; mov [TickCounter_1],eax |
@@WaitHDReady: |
; Ïðîâåðèòü âðåìÿ îæèäàíè |
dec ecx |
; cmp ecx,0 |
jz @@Err1 |
; mov eax,[timer_ticks] |
; sub eax,[TickCounter_1] |
; cmp eax,300 ;îæèäàòü 300 òèêîâ |
; ja @@Err1 ;îøèáêà òàéì-àóòà |
; Ïðî÷èòàòü ðåãèñòð ñîñòîÿíè |
in AL, DX |
; Ïðîâåðèòü ñîñòîÿíèå ñèãíàëà BSY |
test AL, 80h |
jnz @@WaitHDReady |
; Ïðîâåðèòü ñîñòîÿíèå ñèãíàëà DRQ |
test AL, 08h |
jnz @@WaitHDReady |
; Çàãðóçèòü êîìàíäó â ðåãèñòðû êîíòðîëëåðà |
cli |
mov DX, [ATABasePortAddr] |
inc DX ;ðåãèñòð "îñîáåííîñòåé" |
mov AL, [ATAFeatures] |
out DX, AL |
inc DX ;ñ÷åò÷èê ñåêòîðîâ |
mov AL, [ATASectorCount] |
out DX, AL |
inc DX ;ðåãèñòð íîìåðà ñåêòîðà |
mov AL, [ATASectorNumber] |
out DX, AL |
inc DX ;íîìåð öèëèíäðà (ìëàäøèé áàéò) |
mov AX, [ATACylinder] |
out DX, AL |
inc DX ;íîìåð öèëèíäðà (ñòàðøèé áàéò) |
mov AL, AH |
out DX, AL |
inc DX ;íîìåð ãîëîâêè/íîìåð äèñêà |
mov AL, [DiskNumber] |
shl AL, 4 |
cmp [ATAHead], 0Fh;ïðîâåðèòü íîìåð ãîëîâêè |
ja @@Err5 |
or AL, [ATAHead] |
or AL, 10100000b |
mov AH, [ATAAddressMode] |
shl AH, 6 |
or AL, AH |
out DX, AL |
; Ïîñëàòü êîìàíäó |
mov AL, [ATACommand] |
inc DX ;ðåãèñòð êîìàíä |
out DX, AL |
sti |
; Ñáðîñèòü ïðèçíàê îøèáêè |
mov [DevErrorCode], 0 |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Err1: |
mov [DevErrorCode], 1 |
ret |
@@Err2: |
mov [DevErrorCode], 2 |
ret |
@@Err3: |
mov [DevErrorCode], 3 |
ret |
@@Err4: |
mov [DevErrorCode], 4 |
ret |
@@Err5: |
mov [DevErrorCode], 5 |
; Çàâåðøåíèå ðàáîòû ïðîãðàììû |
ret |
;************************************************* |
;* ×ÒÅÍÈÅ ÈÄÅÍÒÈÔÈÊÀÒÎÐÀ ÓÑÒÐÎÉÑÒÂÀ ATAPI * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà; * |
;* DiskNumber - íîìåð äèñêà íà êàíàëå. * |
;* Èäåíòèôèêàöèîííûé áëîê äàííûõ ñ÷èòûâàåòñÿ * |
;* â ìàññèâ Sector512. * |
;************************************************* |
ReadCD_ID: |
; Çàäàòü ðåæèì CHS |
mov [ATAAddressMode], 0 |
; Ïîñëàòü êîìàíäó èäåíòèôèêàöèè óñòðîéñòâà |
mov [ATAFeatures], 0 |
mov [ATASectorCount], 0 |
mov [ATASectorNumber], 0 |
mov [ATACylinder], 0 |
mov [ATAHead], 0 |
mov [ATACommand], 0A1h |
call SendCommandToHDD |
cmp [DevErrorCode], 0;ïðîâåðèòü êîä îøèáêè |
jne @@End_1 ;çàêîí÷èòü, ñîõðàíèâ êîä îøèáêè |
; Îæèäàòü ãîòîâíîñòü äàííûõ HDD |
mov DX, [ATABasePortAddr] |
add DX, 7 ;ïîðò 1õ7h |
mov ecx, 0xffff |
@@WaitCompleet_1: |
; Ïðîâåðèòü âðåì |
dec ecx |
; cmp ecx,0 |
jz @@Error1_1 ;îøèáêà òàéì-àóòà |
; Ïðîâåðèòü ãîòîâíîñòü |
in AL, DX |
test AL, 80h ;ñîñòîÿíèå ñèãíàëà BSY |
jnz @@WaitCompleet_1 |
test AL, 1 ;ñîñòîÿíèå ñèãíàëà ERR |
jnz @@Error6_1 |
test AL, 08h ;ñîñòîÿíèå ñèãíàëà DRQ |
jz @@WaitCompleet_1 |
; Ïðèíÿòü áëîê äàííûõ îò êîíòðîëëåðà |
; mov AX,DS |
; mov ES,AX |
mov EDI, Sector512 ;offset Sector512 |
mov DX, [ATABasePortAddr];ïîðò 1x0h |
mov CX, 256;÷èñëî ñ÷èòûâàåìûõ ñëîâ |
rep insw |
ret |
; Çàïèñàòü êîä îøèáêè |
@@Error1_1: |
mov [DevErrorCode], 1 |
ret |
@@Error6_1: |
mov [DevErrorCode], 6 |
@@End_1: |
ret |
;************************************************* |
;* ÑÁÐÎÑ ÓÑÒÐÎÉÑÒÂÀ * |
;* Âõîäíûå ïàðàìåòðû ïåðåäàþòñÿ ÷åðåç ãëîáàëüíûå * |
;* ïåðåìåííûå: * |
;* ChannelNumber - íîìåð êàíàëà (1 èëè 2); * |
;* DiskNumber - íîìåð äèñêà (0 èëè 1). * |
;************************************************* |
DeviceReset: |
; Ïðîâåðèòü êîððåêòíîñòü íîìåðà êàíàëà |
mov BX, [ChannelNumber] |
cmp BX, 1 |
jb @@Err3_2 |
cmp BX, 2 |
ja @@Err3_2 |
; Óñòàíîâèòü áàçîâûé àäðåñ |
dec BX |
shl BX, 1 |
movzx ebx, bx |
mov DX, [ebx+StandardATABases] |
mov [ATABasePortAddr], DX |
; Âûáðàòü íóæíûé äèñê |
add DX, 6 ;àäðåñ ðåãèñòðà ãîëîâîê |
mov AL, [DiskNumber] |
cmp AL, 1 ;ïðîâåðèòü íîìåðà äèñêà |
ja @@Err4_2 |
shl AL, 4 |
or AL, 10100000b |
out DX, AL |
; Ïîñëàòü êîìàíäó "Ñáðîñ" |
mov AL, 08h |
inc DX ;ðåãèñòð êîìàíä |
out DX, AL |
mov ecx, 0x80000 |
@@WaitHDReady_1: |
; Ïðîâåðèòü âðåìÿ îæèäàíè |
dec ecx |
; cmp ecx,0 |
je @@Err1_2 ;îøèáêà òàéì-àóòà |
; Ïðî÷èòàòü ðåãèñòð ñîñòîÿíè |
in AL, DX |
; Ïðîâåðèòü ñîñòîÿíèå ñèãíàëà BSY |
test AL, 80h |
jnz @@WaitHDReady_1 |
; Ñáðîñèòü ïðèçíàê îøèáêè |
mov [DevErrorCode], 0 |
ret |
; Îáðàáîòêà îøèáîê |
@@Err1_2: |
mov [DevErrorCode], 1 |
ret |
@@Err3_2: |
mov [DevErrorCode], 3 |
ret |
@@Err4_2: |
mov [DevErrorCode], 4 |
; Çàïèñàòü êîä îøèáêè |
ret |
EndFindHDD: |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect/disks.inc |
---|
0,0 → 1,15 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect/getcache.inc |
---|
0,0 → 1,212 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 @f |
mov eax, 128*1024 |
@@: |
.continue: |
mov [cache_ide0_size], eax |
mov [cache_ide1_size], eax |
mov [cache_ide2_size], eax |
mov [cache_ide3_size], eax |
xor eax, eax |
mov [hdd_appl_data], 1;al |
mov [cd_appl_data], 1 |
mov ch, [DRIVE_DATA+1] |
mov cl, ch |
and cl, 11b |
je .ide2 |
mov esi, cache_ide3 |
call get_cache_ide |
.ide2: |
mov cl, ch |
shr cl, 2 |
and cl, 11b |
je .ide1 |
mov esi, cache_ide2 |
call get_cache_ide |
.ide1: |
mov cl, ch |
shr cl, 4 |
and cl, 11b |
je .ide0 |
mov esi, cache_ide1 |
call get_cache_ide |
.ide0: |
mov cl, ch |
shr cl, 6 |
and cl, 11b |
je @f |
mov esi, cache_ide0 |
call get_cache_ide |
@@: |
xor ecx, ecx |
cmp [NumBiosDisks], ecx |
jz .endbd |
mov esi, BiosDiskCaches |
.loopbd: |
push ecx |
movsx ecx, byte [BiosDisksData+ecx*4+2] |
inc ecx |
jz .getbd |
add ecx, ecx |
movzx eax, byte [DRIVE_DATA+1] |
shl eax, cl |
and ah, 3 |
cmp ah, 1 |
jz .contbd |
pop ecx |
mov byte [BiosDisksData+ecx*4+2], -1 |
push ecx |
.getbd: |
mov eax, [cache_ide0_size] |
mov [esi+cache_ide0_size-cache_ide0], eax |
mov cl, 1 |
call get_cache_ide |
.contbd: |
pop ecx |
add esi, cache_ide1-cache_ide0 |
inc ecx |
cmp ecx, [NumBiosDisks] |
jb .loopbd |
.endbd: |
jmp end_get_cache |
get_cache_ide: |
and [esi+cache_ide0_search_start-cache_ide0], 0 |
and [esi+cache_ide0_appl_search_start-cache_ide0], 0 |
push ecx |
stdcall kernel_alloc, [esi+cache_ide0_size-cache_ide0] |
mov [esi+cache_ide0_pointer-cache_ide0], eax |
pop ecx |
mov edx, eax |
mov eax, [esi+cache_ide0_size-cache_ide0] |
shr eax, 3 |
mov [esi+cache_ide0_system_data_size-cache_ide0], eax |
mov ebx, eax |
imul eax, 7 |
mov [esi+cache_ide0_appl_data_size-cache_ide0], eax |
add ebx, edx |
mov [esi+cache_ide0_data_pointer-cache_ide0], ebx |
cmp cl, 10b |
je .cd |
push ecx |
mov eax, [esi+cache_ide0_system_data_size-cache_ide0] |
call calculate_for_hd |
add eax, [esi+cache_ide0_pointer-cache_ide0] |
mov [esi+cache_ide0_system_data-cache_ide0], eax |
mov [esi+cache_ide0_system_sad_size-cache_ide0], ecx |
push edi |
mov edi, [esi+cache_ide0_pointer-cache_ide0] |
call clear_ide_cache |
pop edi |
mov eax, [esi+cache_ide0_appl_data_size-cache_ide0] |
call calculate_for_hd |
add eax, [esi+cache_ide0_data_pointer-cache_ide0] |
mov [esi+cache_ide0_appl_data-cache_ide0], eax |
mov [esi+cache_ide0_appl_sad_size-cache_ide0], ecx |
push edi |
mov edi, [esi+cache_ide0_data_pointer-cache_ide0] |
call clear_ide_cache |
pop edi |
pop ecx |
ret |
.cd: |
push ecx |
mov eax, [esi+cache_ide0_system_data_size-cache_ide0] |
call calculate_for_cd |
add eax, [esi+cache_ide0_pointer-cache_ide0] |
mov [esi+cache_ide0_system_data-cache_ide0], eax |
mov [esi+cache_ide0_system_sad_size-cache_ide0], ecx |
push edi |
mov edi, [esi+cache_ide0_pointer-cache_ide0] |
call clear_ide_cache |
pop edi |
mov eax, [esi+cache_ide0_appl_data_size-cache_ide0] |
call calculate_for_cd |
add eax, [esi+cache_ide0_data_pointer-cache_ide0] |
mov [esi+cache_ide0_appl_data-cache_ide0], eax |
mov [esi+cache_ide0_appl_sad_size-cache_ide0], ecx |
push edi |
mov edi, [esi+cache_ide0_data_pointer-cache_ide0] |
call clear_ide_cache |
pop edi |
pop ecx |
ret |
calculate_for_hd: |
push eax |
mov ebx, eax |
shr eax, 9 |
shl eax, 3 |
sub ebx, eax |
shr ebx, 9 |
mov ecx, ebx |
shl ebx, 9 |
pop eax |
sub eax, ebx |
dec 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: |
; mov [cache_ide0_pointer],HD_CACHE |
; mov [cache_ide0_system_data],HD_CACHE+65536 |
; mov [cache_ide0_system_sad_size],1919 |
popa |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/detect |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/hid/keyboard.inc |
---|
0,0 → 1,552 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
VKEY_LSHIFT = 0000000000000001b |
VKEY_RSHIFT = 0000000000000010b |
VKEY_LCONTROL = 0000000000000100b |
VKEY_RCONTROL = 0000000000001000b |
VKEY_LALT = 0000000000010000b |
VKEY_RALT = 0000000000100000b |
VKEY_CAPSLOCK = 0000000001000000b |
VKEY_NUMLOCK = 0000000010000000b |
VKEY_SCRLOCK = 0000000100000000b |
VKEY_LWIN = 0000001000000000b |
VKEY_RWIN = 0000010000000000b |
VKEY_SHIFT = 0000000000000011b |
VKEY_CONTROL = 0000000000001100b |
VKEY_ALT = 0000000000110000b |
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[TASK_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 |
push sizeof.KEYBOARD |
pop eax |
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[TASK_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 |
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 |
.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 |
test [kb_state], VKEY_NUMLOCK |
jz .dowrite |
cmp cl, 0xE0 |
jz .dowrite |
cmp ch, 55 |
jnz @f |
mov bl, 0x2A ;* |
jmp .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 |
mov [KEY_COUNT+eax], bl |
.exit.irq1: |
mov [check_idle_semaphore], 5 |
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 |
mov al, [esp+8] |
call kb_write |
stdcall enable_irq, 1 |
ret 8 |
;// mike.dld ] |
check_lights_state: |
mov al, [kb_lights] |
cmp al, [old_kb_lights] |
jz .nothing |
mov [old_kb_lights], al |
call set_lights |
.nothing: |
ret |
;--------------------------------------------------------------------- |
numlock_map: |
db 0x37 ;Num 7 |
db 0x38 ;Num 8 |
db 0x39 ;Num 9 |
db 0x2D ;Num - |
db 0x34 ;Num 4 |
db 0x35 ;Num 5 |
db 0x36 ;Num 6 |
db 0x2B ;Num + |
db 0x31 ;Num 1 |
db 0x32 ;Num 2 |
db 0x33 ;Num 3 |
db 0x30 ;Num 0 |
db 0x2E ;Num . |
;--------------------------------------------------------------------- |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/hid/mousedrv.inc |
---|
0,0 → 1,552 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 0x0 |
mousedata dd 0x0 |
Y_UNDER_sub_CUR_hot_y_add_curh: |
dw 0 |
Y_UNDER_subtraction_CUR_hot_y: |
dw 0 |
X_UNDER_sub_CUR_hot_x_add_curh: |
dw 0 |
X_UNDER_subtraction_CUR_hot_x: |
dw 0 |
endg |
iglobal |
;-------------------------------------- |
align 4 |
mouse_delay dd 10 |
mouse_speed_factor: |
dd 3 |
mouse_timer_ticks dd 0 |
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 |
;-------------------------------------- |
align 4 |
@@: |
pushad |
xor ecx, ecx |
xor edx, edx |
;-------------------------------------- |
align 4 |
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, [_WinMapAddress] |
movzx edx, byte [ebx+eax] |
shl edx, 8 |
mov esi, [edx+SLOT_BASE+APPDATA.cursor] |
cmp esi, [current_cursor] |
je .draw |
mov eax, [TASK_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 |
call getpixel |
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 2 |
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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.end: |
mov eax, ecx |
ret |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
@@: |
popfd |
;-------------------------------------- |
align 4 |
nodmp: |
popad |
ret |
;----------------------------------------------------------------------------- |
align 4 |
proc set_mouse_data stdcall, BtnState:dword, XMoving:dword, YMoving:dword, VScroll:dword, HScroll:dword |
mov eax, [BtnState] |
mov [BTN_DOWN], eax |
mov eax, [XMoving] |
call mouse_acceleration |
add ax, [MOUSE_X];[XCoordinate] |
cmp ax, 0 |
jge @@M1 |
mov eax, 0 |
jmp @@M2 |
;-------------------------------------- |
align 4 |
@@M1: |
cmp ax, [Screen_Max_X];ScreenLength |
jl @@M2 |
mov ax, [Screen_Max_X];ScreenLength-1 |
;-------------------------------------- |
align 4 |
@@M2: |
mov [MOUSE_X], ax;[XCoordinate] |
mov eax, [YMoving] |
neg eax |
call mouse_acceleration |
add ax, [MOUSE_Y];[YCoordinate] |
cmp ax, 0 |
jge @@M3 |
mov ax, 0 |
jmp @@M4 |
;-------------------------------------- |
align 4 |
@@M3: |
cmp ax, [Screen_Max_Y];ScreenHeigth |
jl @@M4 |
mov ax, [Screen_Max_Y];ScreenHeigth-1 |
;-------------------------------------- |
align 4 |
@@M4: |
mov [MOUSE_Y], ax;[YCoordinate] |
mov eax, [VScroll] |
add [MOUSE_SCROLL_V], ax |
mov eax, [HScroll] |
add [MOUSE_SCROLL_H], ax |
mov [mouse_active], 1 |
mov eax, [timer_ticks] |
mov [mouse_timer_ticks], eax |
ret |
endp |
;----------------------------------------------------------------------------- |
align 4 |
mouse_acceleration: |
push eax |
mov eax, [timer_ticks] |
sub eax, [mouse_timer_ticks] |
cmp eax, [mouse_delay] |
pop eax |
ja @f |
;push edx |
imul eax, [mouse_speed_factor] |
;pop edx |
;-------------------------------------- |
align 4 |
@@: |
ret |
;----------------------------------------------------------------------------- |
Property changes: |
Added: svn:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/hid/set_dtc.inc |
---|
0,0 → 1,203 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/hid |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/kernel32.inc |
---|
0,0 → 1,260 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; KERNEL32.INC ;; |
;; ;; |
;; Included 32 bit kernel files for MenuetOS ;; |
;; ;; |
;; This file is kept separate as it will be easier to ;; |
;; maintain and compile with an automated SETUP program ;; |
;; in the future. ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
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 |
struct DISPMODE |
width dw ? |
height dw ? |
bpp dw ? |
freq dw ? |
ends |
; constants definition |
WSTATE_NORMAL = 00000000b |
WSTATE_MAXIMIZED = 00000001b |
WSTATE_MINIMIZED = 00000010b |
WSTATE_ROLLEDUP = 00000100b |
WSTATE_REDRAW = 00000001b |
WSTATE_WNDDRAWN = 00000010b |
WSTYLE_HASCAPTION = 00010000b |
WSTYLE_CLIENTRELATIVE = 00100000b |
struct TASKDATA |
event_mask dd ? |
pid dd ? |
dw ? |
state db ? |
db ? |
dw ? |
wnd_number db ? |
db ? |
mem_start dd ? |
counter_sum dd ? |
counter_add dd ? |
cpu_usage dd ? |
ends |
TSTATE_RUNNING = 0 |
TSTATE_RUN_SUSPENDED = 1 |
TSTATE_WAIT_SUSPENDED = 2 |
TSTATE_ZOMBIE = 3 |
TSTATE_TERMINATING = 4 |
TSTATE_WAITING = 5 |
TSTATE_FREE = 9 |
; structures definition |
struct WDATA |
box BOX |
cl_workarea dd ? |
cl_titlebar dd ? |
cl_frames dd ? |
reserved db ? |
fl_wstate db ? |
fl_wdrawn db ? |
fl_redraw db ? |
ends |
label WDATA.fl_wstyle byte at WDATA.cl_workarea + 3 |
struct DBG_REGS |
dr0 dd ? |
dr1 dd ? |
dr2 dd ? |
dr3 dd ? |
dr7 dd ? |
ends |
struct APPDATA |
app_name rb 11 |
rb 5 |
fpu_state dd ? ;+16 |
ev_count_ dd ? ;unused ;+20 |
exc_handler dd ? ;+24 |
except_mask dd ? ;+28 |
pl0_stack dd ? ;+32 |
heap_base dd ? ;+36 |
heap_top 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 |
dlls_list_ptr dd ? ;+108 |
event_filter dd ? ;+112 |
rb 12 ;+116 |
wnd_shape dd ? ;+128 |
wnd_shape_scale dd ? ;+132 |
dd ? ;+136 |
mem_size dd ? ;+140 |
saved_box BOX |
ipc_start dd ? |
ipc_size dd ? |
event_mask dd ? |
debugger_slot dd ? |
terminate_protection dd ? |
keyboard_mode db ? |
rb 3 |
dir_table dd ? |
dbg_event_mem dd ? |
dbg_regs DBG_REGS |
wnd_caption dd ? |
wnd_clientbox BOX |
ends |
; Core functions |
include "core/sync.inc" ; macros for synhronization objects |
include "core/sys32.inc" ; process management |
include "core/sched.inc" ; process scheduling |
include "core/syscall.inc" ; system call |
include "core/fpu.inc" ; all fpu/sse support |
include "core/memory.inc" |
include "core/heap.inc" ; kernel and app heap |
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" ; virtual-8086 manager |
include "core/irq.inc" ; irq handling functions |
include "core/apic.inc" ; Interrupt Controller functions |
include "core/timers.inc" |
; GUI stuff |
include "gui/window.inc" |
include "gui/event.inc" |
include "gui/font.inc" |
include "gui/button.inc" |
; shutdown |
; file system |
include "blkdev/disk.inc" ; support for plug-n-play disks |
include "blkdev/disk_cache.inc" ; caching for plug-n-play disks |
include "fs/fs.inc" ; syscall |
include "fs/fat32.inc" ; read / write for fat32 filesystem |
include "fs/ntfs.inc" ; read / write for ntfs filesystem |
include "fs/fat12.inc" ; read / write for fat12 filesystem |
include "blkdev/rd.inc" ; ramdisk read /write |
include "fs/fs_lfn.inc" ; syscall, version 2 |
include "fs/iso9660.inc" ; read for iso9660 filesystem CD |
include "fs/ext2.inc" ; read / write for ext2 filesystem |
; sound |
include "sound/playnote.inc" ; player Note for Speaker PC |
; display |
;include "video/vesa12.inc" ; Vesa 1.2 functions |
include "video/vesa20.inc" ; Vesa 2.0 functions |
include "video/blitter.inc" ; |
include "video/vga.inc" ; VGA 16 color functions |
include "video/cursors.inc" ; cursors functions |
; Network Interface & TCPIP Stack |
include "network/stack.inc" |
;include "drivers/uart.inc" |
; Mouse pointer |
include "gui/mouse.inc" |
; Window skinning |
include "gui/skincode.inc" |
; Pci functions |
include "bus/pci/pci32.inc" |
; Floppy drive controller |
include "blkdev/fdc.inc" |
include "blkdev/flp_drv.inc" |
; IDE cache |
include "blkdev/ide_cache.inc" |
; HD drive controller |
include "blkdev/hd_drv.inc" |
; CD drive controller |
include "blkdev/cdrom.inc" |
include "blkdev/cd_drv.inc" |
; Character devices |
include "hid/keyboard.inc" |
include "hid/mousedrv.inc" |
; setting date,time,clock and alarm-clock |
include "hid/set_dtc.inc" |
;% -include |
;parser file names |
include "fs/parse_fn.inc" |
; work with conf lib |
include "core/conf_lib.inc" |
; load external lib |
include "core/ext_lib.inc" |
; list of external functions |
include "imports.inc" |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/kernelsp.inc |
---|
0,0 → 1,4 |
; ste archivo debe ser editado con codificaci¢n CP866 |
version db 'Kolibri OS versi¢n 0.7.7.0+ ',13,10,13,10,0 |
diff16 "fin del c¢digo del kernel",0,$ |
/kernel/branches/net/memmap.inc |
---|
0,0 → 1,280 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; |
; MEMORY MAP |
; |
; Boot: |
; |
; 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:9010 byte mouse port - not used |
; 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 not used anymore (0 or 1 : enable system log display) |
; 0:901E byte 0 or 1 : enable direct lfb write, paging disabled |
; 0:901F byte DMA write : 1=yes, 2=no |
; 0:9020 8bytes pci data |
; 0:9030 byte VRR start enabled 1, 2-no |
; 0:9031 word IDEContrRegsBaseAddr |
; 0x9040 - dword - entry point of APM BIOS |
; 0x9044 - word - version (BCD) |
; 0x9046 - word - flags |
; 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 -> 6CBFF kernel, 32-bit run-time code (up to 371 Kb) |
; 0x8006CC00 -> 6DBFF stack at boot time (4Kb) |
; |
; 0x8006DC00 -> 6E5FF free (2560) |
; 0x8006E600 -> 6Efff free (2560) |
; 0x8006F000 -> 6FFFF main page directory |
; 0x80070000 -> 7FFFF data of retrieved disks and partitions (Mario79) |
; 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 tmp (64k) - unused? |
; 0x800A0000 -> AFFFF screen access area |
; 0x800B0000 -> FFFFF bios rest in peace -area (320k) ? |
; 0x80100000 -> 27FFFF diskette image (1m5) |
; 0x80280000 -> 281FFF ramdisk fat (8k) |
; 0x80282000 -> 283FFF floppy fat (8k) |
; |
; 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 -> 2F3FFF tcp memory stack_data_start eth_data_start (16k) |
; |
; 0x802F4000 -> 30ffff stack_data | stack_data_end (112k) |
; |
; 0x80310000 -> 317fff resendQ (32k) |
; |
; 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/video/blitter.inc |
---|
0,0 → 1,429 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
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: |
;eax= 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 |
jae @F |
mov eax, ecx |
@@: |
mov [edi+RECT.left], eax |
cmp ebx, edx ;right <= clip.right |
jle @f |
mov ebx, edx |
@@: |
mov [edi+RECT.right], ebx |
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 |
jae @F |
mov eax, ecx |
@@: |
mov [edi+RECT.top], eax |
cmp ebx, edx ;bottom <= clip.bottom |
jle @f |
mov ebx, edx |
@@: |
mov [edi+RECT.bottom], ebx |
pop ebx |
xor eax, eax |
ret |
.fail: |
pop ebx |
mov eax, 1 |
ret |
align 4 |
blit_clip: |
.sx0 equ 8 |
.sy0 equ 12 |
.sx1 equ 16 |
.sy1 equ 20 |
.dx0 equ 24 |
.dy0 equ 28 |
.dx1 equ 32 |
.dy1 equ 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 |
test eax, eax |
mov esi, 1 |
jnz .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 |
test eax, eax |
mov esi, 1 |
jnz .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 |
xor esi, esi |
.done: |
mov eax, esi |
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 |
sub esp, 72 |
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+56], eax |
mov eax, [ecx+36] |
mov [esp+60], eax |
mov ecx, esp |
call blit_clip |
test eax, eax |
jne .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] |
mov ecx, ebx |
add ecx, [esp+BLITTER.w] |
shl ecx, 16 |
mov cx, bp |
add ecx, [esp+BLITTER.h] |
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, [_WinMapAddress] |
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.bpp], 32 |
jne .core_24 |
lea edi, [edi+ebx*4] |
mov ebx, [CURRENT_TASK] |
align 4 |
.outer32: |
xor ecx, ecx |
align 4 |
.inner32: |
cmp [ebp+ecx], bl |
jne .skip |
;-------------------------------------- |
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 |
;-------------------------------------- |
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: |
; store to real LFB |
mov [LFB_BASE+edi+ecx*4], eax |
pop eax |
;-------------------------------------- |
align 4 |
.skip: |
inc ecx |
dec edx |
jnz .inner32 |
add esi, [esp+BLITTER.stride] |
add edi, [_display.pitch] |
add ebp, [_display.width] |
mov edx, [esp+BLITTER.w] |
dec [esp+BLITTER.h] |
jnz .outer32 |
.done: |
; call [draw_pointer] |
; call __sys_draw_pointer |
.L57: |
add esp, 72 |
pop ebx |
pop esi |
pop edi |
pop ebp |
ret |
.core_24: |
lea ebx, [ebx+ebx*2] |
lea edi, [LFB_BASE+edi+ebx] |
mov ebx, [CURRENT_TASK] |
align 4 |
.outer24: |
mov [esp+64], edi |
xor ecx, ecx |
align 4 |
.inner24: |
cmp [ebp+ecx], bl |
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+64] |
inc ecx |
dec edx |
jnz .inner24 |
add esi, [esp+BLITTER.stride] |
add edi, [_display.pitch] |
add ebp, [_display.width] |
mov edx, [esp+BLITTER.w] |
dec [esp+BLITTER.h] |
jnz .outer24 |
jmp .done |
/kernel/branches/net/video/cursors.inc |
---|
0,0 → 1,1049 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
LOAD_FROM_FILE equ 0 |
LOAD_FROM_MEM equ 1 |
LOAD_INDIRECT equ 2 |
LOAD_SYSTEM equ 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] |
ret |
;-------------------------------------- |
align 4 |
.fail: |
mov eax, [def_cursor] |
mov ebx, [current_slot] |
xchg eax, [ebx+APPDATA.cursor] |
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_TASK] |
shl eax, 5 |
mov eax, [CURRENT_TASK+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_TASK] |
shl ebx, 5 |
mov ebx, [CURRENT_TASK+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, [BytesPerScanLine] |
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, [BytesPerScanLine] |
mov ecx, [cur.w] |
rep movsd |
dec edx |
jnz @B |
pop edi |
;-------------------------------------- |
align 4 |
.ret: |
pop esi |
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, [Screen_Max_X] |
jbe @F |
mov ebx, [Screen_Max_X] |
;-------------------------------------- |
align 4 |
@@: |
cmp edi, [Screen_Max_Y] |
jbe @F |
mov edi, [Screen_Max_Y] |
;-------------------------------------- |
align 4 |
@@: |
mov [cur.right], ebx |
mov [cur.bottom], edi |
sub ebx, [x] |
sub edi, [y] |
inc ebx |
inc edi |
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, [BytesPerScanLine] |
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, [BytesPerScanLine] |
;-------------------------------------- |
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, [Screen_Max_X] |
jbe @F |
mov ebx, [Screen_Max_X] |
;-------------------------------------- |
align 4 |
@@: |
cmp edi, [Screen_Max_Y] |
jbe @F |
mov edi, [Screen_Max_Y] |
;-------------------------------------- |
align 4 |
@@: |
mov [cur.right], ebx |
mov [cur.bottom], edi |
sub ebx, [x] |
sub edi, [y] |
inc ebx |
inc edi |
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, [BytesPerScanLine] |
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, [BytesPerScanLine] |
;-------------------------------------- |
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 |
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 [ScreenBPP], byte 32 |
je @f |
sub eax, ebx |
;-------------------------------------- |
align 4 |
@@: |
add eax, cur_saved_data |
mov ecx, [eax] |
and ecx, 0xffffff |
add 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 [ScreenBPP], byte 24 |
je .24 |
and eax, 0xFFFFFF |
mov [ecx + cur_saved_data], eax ;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 |
cmp [SCR_MODE], word 0x13 |
jbe .fail |
test word [SCR_MODE], 0x4000 |
jz .fail |
; jmp .fail |
mov ebx, restore_32 |
mov ecx, move_cursor_32 |
movzx eax, byte [ScreenBPP] |
cmp eax, 32 |
je @F |
mov ebx, restore_24 |
mov ecx, move_cursor_24 |
cmp eax, 24 |
jne .fail |
;-------------------------------------- |
align 4 |
@@: |
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 |
cmp [ScreenBPP], byte 32 |
je .32 |
mov [PUTPIXEL], dword Vesa20_putpixel24_new |
jmp @f |
;-------------------------------------- |
align 4 |
.32: |
mov [PUTPIXEL], dword Vesa20_putpixel32_new |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
.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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/video/vesa12.inc |
---|
0,0 → 1,1004 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 equ 0 |
S3_VIDEO equ 0 |
INTEL_VIDEO equ 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/video/vesa20.inc |
---|
0,0 → 1,2150 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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 $ |
; If you're planning to write your own video driver I suggest |
; you replace the VESA12.INC file and see those instructions. |
;Screen_Max_X equ 0xfe00 |
;Screen_Max_Y equ 0xfe04 |
;BytesPerScanLine equ 0xfe08 |
;LFBAddress equ 0xfe80 |
;ScreenBPP equ 0xfbf1 |
;----------------------------------------------------------------------------- |
; getpixel |
; |
; in: |
; eax = x coordinate |
; ebx = y coordinate |
; |
; ret: |
; ecx = 00 RR GG BB |
;----------------------------------------------------------------------------- |
align 4 |
getpixel: |
push eax ebx edx edi |
call dword [GETPIXEL] |
pop edi edx ebx eax |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_getpixel24: |
; eax = x |
; ebx = y |
;-------------------------------------- |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je @f |
cmp [_display.select_cursor], 0 |
jne .no_mouseunder |
;-------------------------------------- |
align 4 |
@@: |
; 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 |
;-------------------------------------- |
align 4 |
.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] |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xffffff |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_getpixel32: |
;-------------------------------------- |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je @f |
cmp [_display.select_cursor], 0 |
jne .no_mouseunder |
;-------------------------------------- |
align 4 |
@@: |
; 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 |
;-------------------------------------- |
align 4 |
.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] |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xffffff |
ret |
;----------------------------------------------------------------------------- |
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 |
;----------------------------------------------------------------------------- |
align 16 |
; 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 |
vesa20_putimage: |
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 |
; \begin{diamond}[20.08.2006] |
; note that WDATA.box.width is one pixel less than real window x-size |
inc ebx |
; \end{diamond}[20.08.2006] |
sub ebx, [putimg.image_cx] |
ja @f |
add esp, putimg.stack_data |
popad |
ret |
;-------------------------------------- |
align 4 |
@@: |
cmp ebx, [putimg.image_sx] |
jbe .end_x |
mov ebx, [putimg.image_sx] |
;-------------------------------------- |
align 4 |
.end_x: |
mov [putimg.real_sx], ebx |
; init real_sy |
mov ebx, [eax-twdw + WDATA.box.height]; ebx = wnd_sy |
; \begin{diamond}[20.08.2006] |
inc ebx |
; \end{diamond}[20.08.2006] |
sub ebx, [putimg.image_cy] |
ja @f |
add esp, putimg.stack_data |
popad |
ret |
;-------------------------------------- |
align 4 |
@@: |
cmp ebx, [putimg.image_sy] |
jbe .end_y |
mov ebx, [putimg.image_sy] |
;-------------------------------------- |
align 4 |
.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, [Screen_Max_X] |
inc eax |
sub eax, [putimg.real_sx] |
mov [putimg.winmap_newline], eax |
; screen new line increment |
mov eax, [BytesPerScanLine] |
movzx ebx, byte [ScreenBPP] |
shr ebx, 3 |
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] |
; movzx ebx, byte [ScreenBPP] |
; shr ebx, 3 |
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, [_WinMapAddress] |
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_TASK] |
cmp byte [ScreenBPP], 32 |
je put_image_end_32 |
;-------------------------------------- |
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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
; store to real LFB |
mov [LFB_BASE+edx], ax |
shr eax, 16 |
mov [LFB_BASE+edx+2], al |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 3 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
dec edi |
jnz .new_line |
;-------------------------------------- |
align 4 |
.finish: |
add esp, putimg.stack_data |
popad |
ret |
;------------------------------------------------------------------------------ |
align 4 |
put_image_end_24_old: |
;-------------------------------------- |
align 4 |
.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 real LFB |
mov [LFB_BASE+edx], ax |
shr eax, 16 |
mov [LFB_BASE+edx+2], al |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 3 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
dec edi |
jnz .new_line |
jmp put_image_end_24.finish |
;------------------------------------------------------------------------------ |
align 4 |
put_image_end_24_new: |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.no_mouse_area: |
pop ecx |
; store to real LFB |
mov [LFB_BASE+edx], ax |
shr eax, 16 |
mov [LFB_BASE+edx+2], al |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 3 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
; store to real LFB |
mov [LFB_BASE+edx], eax |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 4 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
dec edi |
jnz .new_line |
;-------------------------------------- |
align 4 |
.finish: |
add esp, putimg.stack_data |
popad |
cmp [SCR_MODE], dword 0x12 |
jne @f |
call VGA__putimage |
;-------------------------------------- |
align 4 |
@@: |
mov [EGA_counter], 1 |
ret |
;------------------------------------------------------------------------------ |
align 4 |
put_image_end_32_old: |
;-------------------------------------- |
align 4 |
.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 real LFB |
mov [LFB_BASE+edx], eax |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 4 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
dec edi |
jnz .new_line |
jmp put_image_end_32.finish |
;------------------------------------------------------------------------------ |
align 4 |
put_image_end_32_new: |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.no_mouse_area: |
pop ecx |
; store to real LFB |
mov [LFB_BASE+edx], eax |
;-------------------------------------- |
align 4 |
.skip: |
add edx, 4 |
inc ebp |
dec ecx |
jnz .new_x |
add esi, [putimg.line_increment] |
add edx, [putimg.screen_newline];[BytesPerScanLine] |
add ebp, [putimg.winmap_newline];[Screen_Max_X] |
cmp [putimg.ebp], putimage_get1bpp |
jz .correct |
cmp [putimg.ebp], putimage_get2bpp |
jz .correct |
cmp [putimg.ebp], putimage_get4bpp |
jnz @f |
;-------------------------------------- |
align 4 |
.correct: |
mov eax, [putimg.edi] |
mov byte [eax], 80h |
;-------------------------------------- |
align 4 |
@@: |
dec edi |
jnz .new_line |
jmp put_image_end_32.finish |
;------------------------------------------------------------------------------ |
align 4 |
__sys_putpixel: |
; eax = x coordinate |
; ebx = y coordinate |
; ecx = ?? RR GG BB ; 0x01000000 negation |
; 0x02000000 used for draw_rectangle without top line |
; for example drawwindow_III and drawwindow_IV |
; edi = 0x00000001 force |
;;; mov [novesachecksum], dword 0 |
pushad |
cmp [Screen_Max_X], eax |
jb .exit |
cmp [Screen_Max_Y], ebx |
jb .exit |
test edi, 1 ; force ? |
jnz .forced |
; not forced: |
mov edx, [d_width_calc_area + ebx*4] |
add edx, [_WinMapAddress] |
movzx edx, byte [eax+edx] |
cmp edx, [CURRENT_TASK] |
jne .exit |
;-------------------------------------- |
align 4 |
.forced: |
; check if negation |
test ecx, 0x01000000 |
jz .noneg |
call getpixel |
not ecx |
rol ecx, 8 |
mov cl, [esp+32-8+3] |
ror ecx, 8 |
mov [esp+32-8], ecx |
;-------------------------------------- |
align 4 |
.noneg: |
; OK to set pixel |
call dword [PUTPIXEL]; call the real put_pixel function |
;-------------------------------------- |
align 4 |
.exit: |
popad |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_putpixel24: |
; eax = x |
; ebx = y |
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 |
;-------------------------------------- |
align 4 |
@@: |
; store to real LFB |
mov [LFB_BASE+ebx+edi], ax |
shr eax, 16 |
mov [LFB_BASE+ebx+edi+2], al |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_putpixel24_new: |
; eax = x |
; ebx = y |
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 |
;-------------------------------------- |
align 4 |
@@: |
; store to real LFB |
mov [LFB_BASE+ebx+edi], ax |
shr eax, 16 |
mov [LFB_BASE+ebx+edi+2], al |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_putpixel32: |
; eax = x |
; ebx = y |
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 |
;-------------------------------------- |
align 4 |
@@: |
and eax, 0xffffff |
; store to real LFB |
mov [LFB_BASE+edi], eax |
ret |
;----------------------------------------------------------------------------- |
align 4 |
Vesa20_putpixel32_new: |
; eax = x |
; ebx = y |
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 |
;-------------------------------------- |
align 4 |
@@: |
and eax, 0xffffff |
; store to real 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 |
;----------------------------------------------------------------------------- |
align 4 |
__sys_draw_line: |
; draw a line |
; eax = HIWORD = x1 |
; LOWORD = x2 |
; ebx = HIWORD = y1 |
; LOWORD = y2 |
; ecx = color |
; edi = force ? |
pusha |
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 |
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 |
;-------------------------------------- |
align 4 |
.x2lx1: |
neg esi ; get esi absolute value |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.y2ly1: |
neg ebp ; get ebp absolute value |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
;-------------------------------------- |
mov edx, ebp ; edx = counter (number of pixels to draw) |
mov ebp, 1 *65536; <<16 ; ebp = dy = 1.0 |
mov esi, eax ; esi = dx |
jmp .y_rules |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
;-------------------------------------- |
mov edx, esi ; edx = counter (number of pixels to draw) |
mov esi, 1 *65536;<< 16 ; esi = dx = 1.0 |
mov ebp, eax ; ebp = dy |
;-------------------------------------- |
align 4 |
.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 |
;----------------------------------------------------------------------------- |
align 4 |
.draw: |
push eax ebx |
;-------------------------------------- |
; correction for the remainder of the division |
test ah, 0x80 |
jz @f |
add eax, 1 shl 16 |
;-------------------------------------- |
align 4 |
@@: |
;-------------------------------------- |
shr eax, 16 |
;-------------------------------------- |
; correction for the remainder of the division |
test bh, 0x80 |
jz @f |
add ebx, 1 shl 16 |
;-------------------------------------- |
align 4 |
@@: |
;-------------------------------------- |
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 ;negate 0x04000000 save to mouseunder area |
; call [putpixel] |
call __sys_putpixel |
;-------------------------------------- |
align 4 |
.exit: |
add esp, 6*4 |
popa |
; call [draw_pointer] |
ret |
;------------------------------------------------------------------------------ |
align 4 |
hline: |
; draw an horizontal line |
; eax = x1 |
; edx = x2 |
; ebx = y |
; ecx = color |
; edi = force ? |
push eax edx |
cmp edx, eax ; make sure x2 is above x1 |
jge @f |
xchg eax, edx |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
;-------------------------------------- |
align 4 |
@@: |
; call [putpixel] |
call __sys_putpixel |
inc eax |
cmp eax, edx |
jle @b |
pop edx eax |
ret |
;------------------------------------------------------------------------------ |
align 4 |
vline: |
; draw a vertical line |
; eax = x |
; ebx = y1 |
; edx = y2 |
; ecx = color |
; edi = force ? |
push ebx edx |
cmp edx, ebx ; make sure y2 is above y1 |
jge @f |
xchg ebx, edx |
;-------------------------------------- |
align 4 |
@@: |
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area |
;-------------------------------------- |
align 4 |
@@: |
; call [putpixel] |
call __sys_putpixel |
inc ebx |
cmp ebx, edx |
jle @b |
pop edx ebx |
ret |
;------------------------------------------------------------------------------ |
align 4 |
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 |
;-------------------------------------- |
align 4 |
; eax cx |
; ebx cy |
; ecx xe |
; edx ye |
; edi color |
vesa20_drawbar: |
pushad |
sub esp, drbar.stack_data |
mov [drbar.color], edi |
sub edx, ebx |
jle .exit ;// mike.dld, 2005-01-29 |
sub ecx, eax |
jle .exit ;// mike.dld, 2005-01-29 |
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 |
; \begin{diamond}[20.08.2006] |
; note that WDATA.box.width is one pixel less than real window x-size |
inc ebx |
; \end{diamond}[20.08.2006] |
sub ebx, [drbar.bar_cx] |
ja @f |
;-------------------------------------- |
align 4 |
.exit: ;// mike.dld, 2005-01-29 |
add esp, drbar.stack_data |
popad |
xor eax, eax |
inc eax |
ret |
;-------------------------------------- |
align 4 |
@@: |
cmp ebx, [drbar.bar_sx] |
jbe .end_x |
mov ebx, [drbar.bar_sx] |
;-------------------------------------- |
align 4 |
.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 |
; \begin{diamond}[20.08.2006] |
inc ebx |
; \end{diamond} |
sub ebx, [drbar.bar_cy] |
ja @f |
add esp, drbar.stack_data |
popad |
xor eax, eax |
inc eax |
ret |
;-------------------------------------- |
align 4 |
@@: |
cmp ebx, [drbar.bar_sy] |
jbe .end_y |
mov ebx, [drbar.bar_sy] |
;-------------------------------------- |
align 4 |
.end_y: |
mov [drbar.real_sy], ebx |
; line_inc_map |
mov eax, [Screen_Max_X] |
sub eax, [drbar.real_sx] |
inc eax |
mov [drbar.line_inc_map], eax |
; line_inc_scr |
mov eax, [drbar.real_sx] |
movzx ebx, byte [ScreenBPP] |
shr ebx, 3 |
imul eax, ebx |
neg eax |
add eax, [BytesPerScanLine] |
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, [_WinMapAddress] |
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_TASK] ; 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 [ScreenBPP], 24 |
jne draw_bar_end_32 |
;-------------------------------------- |
align 4 |
draw_bar_end_24: |
; eax - color high RRGGBB |
; bl - process num |
; ecx - temp |
; edx - pointer to screen |
; esi - counter |
; edi - counter |
;-------------------------------------- |
; 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 |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.new_x: |
cmp byte [ebp], bl |
jne .skip |
;-------------------------------------- |
; store to real LFB |
mov [edx], ax |
shr eax, 16 |
mov [edx + 2], al |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
;-------------------------------------- |
align 4 |
.end: |
add esp, drbar.stack_data |
popad |
xor eax, eax |
ret |
;------------------------------------------------------------------------------ |
align 4 |
draw_bar_end_24_old: |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.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 real LFB |
mov [edx], ax |
shr eax, 16 |
mov [edx + 2], al |
mov eax, [drbar.color] |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
jmp draw_bar_end_24.end |
;------------------------------------------------------------------------------ |
align 4 |
draw_bar_end_24_new: |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.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 |
; store to real LFB |
;-------------------------------------- |
align 4 |
.no_mouse_area: |
mov [edx], ax |
ror eax, 16 |
mov [edx + 2], al |
rol eax, 16 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
jmp draw_bar_end_24.end |
;------------------------------------------------------------------------------ |
align 4 |
draw_bar_end_32: |
; eax - color high RRGGBB |
; bl - process num |
; ecx - temp |
; edx - pointer to screen |
; esi - counter |
; edi - counter |
;-------------------------------------- |
; 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 |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.new_x: |
cmp byte [ebp], bl |
jne .skip |
;-------------------------------------- |
; store to real LFB |
mov [edx], eax |
mov eax, [drbar.color] |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
;-------------------------------------- |
align 4 |
.end: |
add esp, drbar.stack_data |
popad |
cmp [SCR_MODE], dword 0x12 |
jne @f |
call VGA_draw_bar |
;-------------------------------------- |
align 4 |
@@: |
xor eax, eax |
mov [EGA_counter], 1 |
ret |
;------------------------------------------------------------------------------ |
align 4 |
draw_bar_end_32_old: |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.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 real LFB |
mov [edx], eax |
mov eax, [drbar.color] |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
jmp draw_bar_end_32.end |
;------------------------------------------------------------------------------ |
align 4 |
draw_bar_end_32_new: |
;-------------------------------------- |
align 4 |
.new_y: |
mov edi, [drbar.real_sx] |
;-------------------------------------- |
align 4 |
.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 |
; store to real LFB |
;-------------------------------------- |
align 4 |
.no_mouse_area: |
mov [edx], eax |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
dec esi |
jnz .new_y |
jmp draw_bar_end_32.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 |
;-------------------------------------- |
align 4 |
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 |
add ebp, eax |
cmp [ScreenBPP], byte 24 ; 24 or 32 bpp ? - x size |
jz @f |
add ebp, eax |
;-------------------------------------- |
align 4 |
@@: |
add ebp, LFB_BASE |
; ebp:=Y*BytesPerScanLine+X*BytesPerPixel+AddrLFB |
call calculate_edi |
xchg edi, ebp |
add ebp, [_WinMapAddress] |
; 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 |
;-------------------------------------- |
align 4 |
dp3: |
cmp [ebp], dl |
jnz nbgp |
;-------------------------------------- |
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 |
;-------------------------------------- |
align 4 |
@@: |
and eax, 0xffffff |
; check mouse area for putpixel |
call [_display.check_mouse] |
;-------------------------------------- |
align 4 |
.no_mouseunder: |
; store to real LFB |
mov [edi], ax |
shr eax, 16 |
mov [edi+2], al |
pop ecx eax |
;-------------------------------------- |
align 4 |
nbgp: |
add esi, 3 |
add edi, 3 |
;-------------------------------------- |
align 4 |
@@: |
cmp [ScreenBPP], byte 25 ; 24 or 32 bpp? |
sbb edi, -1 ; +1 for 32 bpp |
; I do not use 'inc eax' because this is slightly slower then 'add eax,1' |
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 |
;-------------------------------------- |
align 4 |
dp4: |
; next scan line |
inc ebx |
cmp ebx, [draw_data+32+RECT.bottom] |
jbe dp2 |
popad |
mov [EGA_counter], 1 |
cmp [SCR_MODE], dword 0x12 |
jne @f |
call VGA_drawbackground |
;-------------------------------------- |
align 4 |
@@: |
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 [Screen_Max_X] |
push eax ; high |
xor eax, eax |
div dword [Screen_Max_X] |
push eax ; low |
; the same for height |
mov eax, [BgrDataHeight] |
dec eax |
xor edx, edx |
div dword [Screen_Max_Y] |
push eax ; high |
xor eax, eax |
div dword [Screen_Max_Y] |
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 |
add ebp, eax |
cmp [ScreenBPP], byte 24 ; 24 or 32 bpp ? - x size |
jz @f |
add ebp, eax |
;-------------------------------------- |
align 4 |
@@: |
; 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 |
;-------------------------------------- |
align 4 |
bgr_resmooth0: |
mov ecx, [esp+8] |
mov edx, [esp+4] |
mov esi, [esp] |
push edi |
mov edi, bgr_cur_line |
call smooth_line |
;-------------------------------------- |
align 4 |
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 |
;-------------------------------------- |
align 4 |
bgr.no2nd: |
pop edi |
;-------------------------------------- |
align 4 |
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) |
;-------------------------------------- |
align 4 |
sdp3a: |
mov eax, [_WinMapAddress] |
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] |
;-------------------------------------- |
align 4 |
.novert: |
push ecx |
; check for hardware cursor |
cmp [_display.select_cursor], select_cursor |
je @f |
cmp [_display.select_cursor], 0 |
jne .no_mouseunder |
;-------------------------------------- |
align 4 |
@@: |
mov ecx, [esp+20+4] ;x |
shl ecx, 16 |
add ecx, [esp+24+4] ;y |
; check mouse area for putpixel |
call [_display.check_mouse] |
;-------------------------------------- |
align 4 |
.no_mouseunder: |
; store to real LFB |
mov [LFB_BASE+edi], ax |
shr eax, 16 |
mov [LFB_BASE+edi+2], al |
pop ecx |
;-------------------------------------- |
align 4 |
snbgp: |
cmp [ScreenBPP], byte 25 |
sbb edi, -4 |
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 |
;-------------------------------------- |
align 4 |
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, [Screen_Max_X] |
add ebp, 1 |
sub edi, eax |
sub edi, eax |
sub edi, eax |
cmp [ScreenBPP], byte 24 |
jz @f |
sub edi, eax |
;-------------------------------------- |
align 4 |
@@: |
add edi, [BytesPerScanLine] |
; 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, [Screen_Max_X] |
inc ecx |
rep movsd |
jmp bgr_resmooth1 |
;-------------------------------------- |
align 4 |
sdpdone: |
add esp, 44 |
popad |
mov [EGA_counter], 1 |
cmp [SCR_MODE], dword 0x12 |
jne @f |
call VGA_drawbackground |
;-------------------------------------- |
align 4 |
@@: |
ret |
uglobal |
;-------------------------------------- |
align 4 |
bgr_cur_line rd 1920 ; maximum width of screen |
bgr_next_line rd 1920 |
;-------------------------------------- |
endg |
;-------------------------------------- |
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] |
;-------------------------------------- |
align 4 |
@@: |
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 |
;-------------------------------------- |
align 4 |
@@: |
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 |
iglobal |
;-------------------------------------- |
align 4 |
overlapping_of_points_ptr dd overlapping_of_points |
;-------------------------------------- |
endg |
;------------------------------------------------------------------------------ |
align 4 |
init_background: |
mov edi, BgrAuxTable |
xor edx, edx |
;-------------------------------------- |
align 4 |
.loop2: |
mov eax, edx |
shl eax, 8 |
neg eax |
mov ecx, 0x200 |
;-------------------------------------- |
align 4 |
.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 |
;-------------------------------------- |
align 4 |
@@: |
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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/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/net/video/vga.inc |
---|
0,0 → 1,534 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. 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], dword 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] ; óìíîæåíèå íà 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]; óìíîæåíèå íà 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/video/arrow.cur |
---|
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes: |
Added: svn:mergeinfo |
Added: svn:mime-type |
+application/octet-stream |
\ No newline at end of property |
/kernel/branches/net/video |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/README.TXT |
---|
0,0 → 1,13 |
This code is experimental, none of the used programming interfaces (API, driver calls,..) are definite solutions. |
Lot of work needs to be done, and descissions need to be made. |
But, everyone is free to explore the code, make suggestions or write parts of the code. |
I'm open for discussion on hidnplayr@gmail.com or as hidnplayr in #kolibrios on the freenode IRC network. |
Some information about API and things under construction can be found on http://wiki.kolibrios.org/wiki/New_stack |
Binary versions can be found at http://builds.kolibrios.org/new-stack/ |
All bug reports may be sent to me via e-mail, or through the bugtracker on http://bugs.kolibrios.org |
Hidnplayr |
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/sys.conf |
---|
0,0 → 1,12 |
[path] |
/rd/1=/sys |
/rd/1/dll=/sys/lib |
[gui] |
mouse_speed=1 |
mouse_delay=0x00A |
[dev] |
sb16=0x220 |
sound_dma=1 |
midibase=0x320 |
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/macros.inc |
---|
0,0 → 1,199 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 |
\} |
} |
$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] |
; may be useful for kernel debugging |
; example 1: |
; dbgstr 'Hello, World!' |
; example 2: |
; dbgstr 'Hello, World!', 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 Mov op1,op2,op3 ; op1 = op2 = op3 |
{ |
mov op2, op3 |
mov op1, op2 |
} |
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+list_fd] |
mov ecx, [entry+list_bk] |
mov [edx+list_bk], ecx |
mov [ecx+list_fd], edx |
} |
if __CPU_type eq p5 ; CMOVcc isnt supported on the P5 |
cmove fix cmovz |
macro cmovz reg1, reg2 { |
local .jumpaddr |
jnz .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
cmovne fix cmovnz |
macro cmovnz reg1, reg2 { |
local .jumpaddr |
jz .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovg reg1, reg2 { |
local .jumpaddr |
jle .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovl reg1, reg2 { |
local .jumpaddr |
jge .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmova reg1, reg2 { |
local .jumpaddr |
jbe .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovb reg1, reg2 { |
local .jumpaddr |
jae .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovae reg1, reg2 { |
local .jumpaddr |
jb .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
macro cmovbe reg1, reg2 { |
local .jumpaddr |
ja .jumpaddr |
mov reg1, reg2 |
.jumpaddr: |
} |
end if |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/data16.inc |
---|
0,0 → 1,91 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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 |
bx_from_load: |
dw 'r1' ; ñòðóêòóðà äëÿ õðàíåíèÿ ïàðàìåòðîâ- îòêóäà ãàøðóçèëèñü, áåðåòñÿ íèæå èç bx ; {SPraid}[13.03.2007] |
; a,b,c,d - âèí÷åñòåðû, r - ðàì äèñê |
; # äèñêà... ñèìâîë, à íå áàéò. '1', à íå 1 |
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 'vrr', parse_vrr |
config_variable 'biosdisks', parse_biosdisks |
config_variable 'imgfrom', parse_imgfrom |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/fdo.inc |
---|
0,0 → 1,444 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
_esp equ esp |
; |
; 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 |
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 ebx, al |
mov eax, 1 |
mov ecx, sys_msg_board |
call ecx ; sys_msg_board |
popad |
ret |
debug_endf |
debug_func fdo_debug_outstr |
debug_beginf |
mov eax, 1 |
.l1: |
dec esi |
js .l2 |
movzx ebx, byte[edx] |
or bl, bl |
jz .l2 |
mov ecx, sys_msg_board |
call ecx ; sys_msg_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 |
@@: |
push 10 |
pop ecx |
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 __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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/imports.inc |
---|
0,0 → 1,27 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/init.inc |
---|
0,0 → 1,591 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
MEM_WB equ 6 ;write-back memory |
MEM_WC equ 1 ;write combined memory |
MEM_UC equ 0 ;uncached memory |
align 4 |
proc mem_test |
; if we have BIOS with fn E820, skip the test |
cmp dword [BOOT_VAR-OS_BASE + 0x9100], 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_VAR-OS_BASE + 0x9100] |
xor eax, eax |
mov [BOOT_VAR-OS_BASE + 0x9104], eax |
mov [BOOT_VAR-OS_BASE + 0x9108], eax |
mov [BOOT_VAR-OS_BASE + 0x910C], edi |
mov [BOOT_VAR-OS_BASE + 0x9110], eax |
.ret: |
ret |
endp |
align 4 |
proc init_mem |
; calculate maximum allocatable address and number of allocatable pages |
mov edi, BOOT_VAR-OS_BASE + 0x9104 |
mov ecx, [edi-4] |
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] |
cmp [edi+16], byte 1 |
jne .unusable |
test eax, 0xFFF |
jz @f |
neg eax |
and eax, 0xFFF |
add [edi], eax |
adc dword [edi+4], 0 |
sub [edi+8], eax |
sbb dword [edi+12], 0 |
jc .unusable |
@@: |
and dword [edi+8], not 0xFFF |
jz .unusable |
; ignore memory after 4 Gb |
cmp dword [edi+4], 0 |
jnz .unusable |
mov eax, [edi] |
cmp dword [edi+12], 0 |
jnz .overflow |
add eax, [edi+8] |
jnc @f |
.overflow: |
mov eax, 0xFFFFF000 |
@@: |
cmp edx, eax |
jae @f |
mov edx, eax |
@@: |
sub eax, [edi] |
mov [edi+8], eax |
add esi, eax |
jmp .usable |
.unusable: |
; and dword [edi+8], 0 |
.usable: |
add edi, 20 |
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_pgdir-OS_BASE |
mov ecx, 4096/4 |
cld |
rep stosd |
mov edx, (sys_pgdir-OS_BASE)+ 0x800; (OS_BASE shr 20) |
bt [cpu_caps-OS_BASE], CAPS_PSE |
jnc .no_PSE |
mov ebx, cr4 |
or ebx, CR4_PSE |
mov eax, PG_LARGE+PG_SW |
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_SW |
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_SW |
mov edi, edx |
.map_kernel_tabs: |
stosd |
add eax, 0x1000 |
dec ecx |
jnz .map_kernel_tabs |
mov dword [sys_pgdir-OS_BASE+(page_tabs shr 20)], sys_pgdir+PG_SW-OS_BASE |
mov edi, (sys_pgdir-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_VAR-OS_BASE + 0x9104 |
mov edx, [ebx-4] |
.scanmap: |
cmp [ebx+16], byte 1 |
jne .next |
mov ecx, [ebx+8] |
shr ecx, 12; ecx = number of pages |
jz .next |
mov edi, [ebx] |
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, 20 |
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 |
; çäåñü ñîçäàþòñÿ äèñêðèïòîðû äëÿ PCI BIOS |
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 |
.BIOS32_not_found: |
.end: |
ret |
align 4 |
proc test_cpu |
locals |
cpu_type dd ? |
cpu_id dd ? |
cpu_Intel dd ? |
cpu_AMD dd ? |
endl |
xor eax, eax |
mov [cpu_type], eax |
mov [cpu_caps-OS_BASE], eax |
mov [cpu_caps+4-OS_BASE], eax |
pushfd |
pop eax |
mov ecx, eax |
xor eax, 0x40000 |
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, 0x200000 |
push eax |
popfd |
pushfd |
pop eax |
xor eax, ecx |
je .end_cpuid |
mov [cpu_id], 1 |
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 ebx, dword [intel_str-OS_BASE] |
jne .check_AMD |
cmp edx, dword [intel_str+4-OS_BASE] |
jne .check_AMD |
cmp ecx, dword [intel_str+8-OS_BASE] |
jne .check_AMD |
mov [cpu_Intel], 1 |
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 |
shr eax, 8 |
and eax, 0x0f |
ret |
.end_cpuid: |
mov eax, [cpu_type] |
ret |
.check_AMD: |
cmp ebx, dword [AMD_str-OS_BASE] |
jne .unknown |
cmp edx, dword [AMD_str+4-OS_BASE] |
jne .unknown |
cmp ecx, dword [AMD_str+8-OS_BASE] |
jne .unknown |
mov [cpu_AMD], 1 |
cmp eax, 1 |
jl .unknown |
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 |
shr eax, 8 |
and eax, 0x0f |
ret |
.unknown: |
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 |
shr eax, 8 |
and eax, 0x0f |
ret |
endp |
iglobal |
align 4 |
acpi_lapic_base dd 0xfee00000 ; default local apic base |
endg |
uglobal |
align 4 |
acpi_rsdp rd 1 |
acpi_rsdt rd 1 |
acpi_madt rd 1 |
acpi_dev_data rd 1 |
acpi_dev_size rd 1 |
acpi_rsdt_base rd 1 |
acpi_madt_base rd 1 |
acpi_ioapic_base rd 1 |
cpu_count rd 1 |
smpt rd 16 |
endg |
ACPI_HI_RSDP_WINDOW_START equ 0x000E0000 |
ACPI_HI_RSDP_WINDOW_END equ 0x00100000 |
ACPI_RSDP_CHECKSUM_LENGTH equ 20 |
ACPI_MADT_SIGN equ 0x43495041 |
acpi_locate: |
push ebx |
mov ebx, ACPI_HI_RSDP_WINDOW_START |
.check: |
cmp [ebx], dword 0x20445352 |
jne .next |
cmp [ebx+4], dword 0x20525450 |
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 |
mov eax, ebx |
pop ebx |
ret |
.next: |
add ebx, 16 |
cmp ebx, ACPI_HI_RSDP_WINDOW_END |
jb .check |
pop ebx |
xor eax, eax |
ret |
align 4 |
rsdt_find: ;ecx= rsdt edx= SIG |
push ebx |
push esi |
lea ebx, [ecx+36] |
mov esi, [ecx+4] |
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: |
call acpi_locate |
test eax, eax |
jz .done |
mov ecx, [eax+16] |
mov edx, ACPI_MADT_SIGN |
mov [acpi_rsdt_base-OS_BASE], ecx |
call rsdt_find |
test eax, eax |
jz .done |
mov [acpi_madt_base-OS_BASE], eax |
mov ecx, [eax+36] |
mov [acpi_lapic_base-OS_BASE], ecx |
mov edi, smpt-OS_BASE |
mov ebx, [ecx+0x20] |
shr ebx, 24 ; read APIC ID |
mov [edi], ebx ; bootstrap always first |
inc [cpu_count-OS_BASE] |
add edi, 4 |
lea edx, [eax+44] |
mov ecx, [eax+4] |
add ecx, eax |
.check: |
mov eax, [edx] |
cmp al, 0 |
jne .io_apic |
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-OS_BASE], 16 |
jae .next |
stosd ; store APIC ID |
inc [cpu_count-OS_BASE] |
.next: |
mov eax, [edx] |
movzx eax, ah |
add edx, eax |
cmp edx, ecx |
jb .check |
.done: |
ret |
.io_apic: |
cmp al, 1 |
jne .next |
mov eax, [edx+4] |
mov [acpi_ioapic_base-OS_BASE], eax |
jmp .next |
Property changes: |
Added: svn:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/kglobals.inc |
---|
0,0 → 1,69 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/proc32.inc |
---|
0,0 → 1,277 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision $ |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ 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 } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ 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 } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ if parmbytes | localbytes |
push ebp |
mov ebp, esp |
if localbytes |
sub esp, localbytes |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
macro epiloguedef procname,flag,parmbytes,localbytes,reglist |
{ irps reg, reglist \{ reverse pop reg \} |
if parmbytes | localbytes |
leave |
end if |
if (flag and 10000b) | (parmbytes=0) |
retn |
else |
retn parmbytes |
end if } |
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 \} |
virtual at ebp+8 |
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 =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $ - (ebp+8) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
macro locals |
\{ virtual at ebp-localbytes+current |
macro label . \\{ deflocal@proc .,:, \\} |
struc db [val] \\{ \common deflocal@proc .,db,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,dw,dp,dd,dt,dq |
restruc rb,rw,rp,rd,rt,rq |
restruc byte,word,dword,pword,tword,qword |
current = $-(ebp-localbytes) |
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-1) shr 2)+1) shl 2 |
end if \} } |
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 } |
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 =dup (=?), val \{ ..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 \} } |
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 } |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/sound/playnote.inc |
---|
0,0 → 1,166 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2011. 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:keywords |
+Rev |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/sound |
---|
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/struct.inc |
---|
0,0 → 1,240 |
; 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 } |
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 \} } |
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 \\\} \\} \} } |
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 \\} \} } |
enable@substruct |
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 \} } |
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 \} } |
/kernel/branches/net/unpacker.inc |
---|
0,0 → 1,528 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2007. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
$Revision$ |
; void __stdcall unpack(void* packed_data, void* unpacked_data); |
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:keywords |
+Revision |
\ No newline at end of property |
Added: svn:mergeinfo |
/kernel/branches/net/build.bat |
---|
0,0 → 1,161 |
@echo off |
cls |
set languages=en |
set drivers=3c59x dec21x4x i8255x mtd80x pcnet32 r6040 rtl8029 rtl8139 rtl8169 sis900 |
set apps=arpcfg icmp netcfg netstat nslookup synergyc tcpserv telnet tftpc zeroconf |
set libs=network |
set targets=all kernel apps libs drivers clean |
call :Check_Target %1 |
for %%a in (all kernel) do if %%a==%target% call :Check_Lang %2 |
call :Target_%target% |
if ERRORLEVEL 0 goto Exit_OK |
echo There was an error executing script. |
echo For any help, please send a report. |
pause |
goto :eof |
:Check_Lang |
set res=%1 |
:Check_Lang_loop |
for %%a in (%languages%) do if %%a==%res% set lang=%res% |
if defined lang goto :eof |
echo Language '%res%' is incorrect |
echo Enter valid language [ %languages% ]: |
set /P res="> |
goto Check_Lang_loop |
goto :eof |
:Check_Target |
set res=%1 |
:Check_Target_loop |
for %%a in (%targets%) do if %%a==%res% set target=%res% |
if defined target goto :eof |
echo Target '%res%' is incorrect |
echo Enter valid target [ %targets% ]: |
set /P res="> |
goto Check_Target_loop |
goto :eof |
:Target_kernel |
echo *** building kernel with language '%lang%' ... |
if not exist bin mkdir bin |
echo lang fix %lang% > lang.inc |
fasm -m 65536 kernel.asm bin\kernel.mnt |
if not %errorlevel%==0 goto :Error_FasmFailed |
erase lang.inc |
goto :eof |
:Target_all |
call :Target_kernel |
call :Target_apps |
call :Target_libs |
call :Target_drivers |
goto :eof |
:Target_apps |
echo *** building applications ... |
if not exist bin\apps mkdir bin\apps |
cd applications |
for %%a in (%apps%) do ( |
fasm -m 65536 %%a\%%a.asm ..\bin\apps\%%a |
if not %errorlevel%==0 goto :Error_FasmFailed |
) |
cd .. |
goto :eof |
:Target_libs |
echo *** building libraries ... |
if not exist bin\lib mkdir bin\lib |
cd applications\libraries |
for %%a in (%libs%) do ( |
fasm -m 65536 %%a\%%a.asm ..\..\bin\lib\%%a.obj |
if not %errorlevel%==0 goto :Error_FasmFailed |
) |
cd ..\.. |
goto :eof |
:Target_drivers |
echo *** building drivers ... |
if not exist bin\drivers mkdir bin\drivers |
cd drivers |
for %%a in (%drivers%) do ( |
fasm -m 65536 %%a.asm ..\bin\drivers\%%a.obj |
if not %errorlevel%==0 goto :Error_FasmFailed |
) |
cd .. |
kpack >nul 2>&1 |
if %errorlevel%==9009 goto :Error_KpackFailed |
echo * |
echo ############################################## |
echo * |
echo Kpack KolibriOS drivers? |
echo * |
set /P res=[y/n]? |
if "%res%"=="y" ( |
echo * |
echo Compressing system |
echo * |
for %%a in (bin\drivers\*.obj) do ( |
echo ================== kpack %%a |
kpack %%a |
if not %errorlevel%==0 goto :Error_KpackFailed |
) |
) |
goto :eof |
:Target_clean |
echo *** cleaning ... |
rmdir /S /Q bin |
goto :Exit_OK |
:Error_FasmFailed |
echo error: fasm execution failed |
erase lang.inc >nul 2>&1 |
echo. |
pause |
exit 1 |
:Error_KpackFailed |
echo *** NOTICE *** |
echo If you want to pack all applications you may |
echo place "kpack" in accessible directory or system %PATH%. |
echo You can get this tool from KolibriOS distribution kit. |
pause |
exit 1 |
:Exit_OK |
echo. |
echo all operations have been done |
pause |
exit 0 |
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net/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. |
Property changes: |
Added: svn:mergeinfo |
/kernel/branches/net |
---|
Property changes: |
Added: svn:ignore |
+bin |