Subversion Repositories Kolibri OS

Rev

Rev 3556 | Rev 3601 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  STACK.INC                                                      ;;
7
;;                                                                 ;;
8
;;  TCP/IP stack for KolibriOS                                     ;;
9
;;                                                                 ;;
10
;;    Written by hidnplayr@kolibrios.org                           ;;
11
;;                                                                 ;;
12
;;     Some parts of code are based on the work of:                ;;
13
;;      Mike Hibbett (menuetos network stack)                      ;;
14
;;      Eugen Brasoveanu (solar os network stack and drivers)      ;;
15
;;      mike.dld (kolibrios socket code)                           ;;
16
;;                                                                 ;;
17
;;     TCP part is based on 4.4BSD                                 ;;
18
;;                                                                 ;;
19
;;          GNU GENERAL PUBLIC LICENSE                             ;;
20
;;             Version 2, June 1991                                ;;
21
;;                                                                 ;;
22
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
23
 
24
$Revision: 3523 $
25
 
26
uglobal
27
        net_10ms        dd ?
28
        net_tmr_count   dw ?
29
endg
30
 
3556 hidnplayr 31
DEBUG_NETWORK_ERROR     = 1
32
DEBUG_NETWORK_VERBOSE   = 0
33
 
3600 hidnplayr 34
NET_DEVICES_MAX         = 16
3545 hidnplayr 35
ARP_BLOCK               = 1             ; true or false
36
 
3600 hidnplayr 37
EPHEMERAL_PORT_MIN      = 49152
38
EPHEMERAL_PORT_MAX      = 61000
3545 hidnplayr 39
MIN_EPHEMERAL_PORT_N    = 0x00C0        ; same in Network byte order (FIXME)
40
MAX_EPHEMERAL_PORT_N    = 0x48EE        ; same in Network byte order (FIXME)
41
 
42
; Ethernet protocol numbers
3600 hidnplayr 43
ETHER_PROTO_ARP                 = 0x0608
44
ETHER_PROTO_IPv4                = 0x0008
45
ETHER_PROTO_IPv6                = 0xDD86
46
ETHER_PROTO_PPP_DISCOVERY       = 0x6388
47
ETHER_PROTO_PPP_SESSION         = 0x6488
3545 hidnplayr 48
 
3600 hidnplayr 49
; Internet protocol numbers
50
IP_PROTO_IP             = 0
51
IP_PROTO_ICMP           = 1
52
IP_PROTO_TCP            = 6
53
IP_PROTO_UDP            = 17
54
 
3545 hidnplayr 55
; PPP protocol numbers
3600 hidnplayr 56
PPP_PROTO_IPv4          = 0x2100
57
PPP_PROTO_IPV6          = 0x5780
58
PPP_PROTO_ETHERNET      = 666           ; FIXME
3545 hidnplayr 59
 
60
;Protocol family
61
AF_UNSPEC               = 0
62
AF_LOCAL                = 1
63
AF_INET4                = 2
64
AF_INET6                = 10
3600 hidnplayr 65
AF_PPP                  = 777           ; FIXME
3545 hidnplayr 66
 
67
; Socket types
68
SOCK_STREAM             = 1
69
SOCK_DGRAM              = 2
70
SOCK_RAW                = 3
71
 
72
; Socket options
73
SO_ACCEPTCON            = 1 shl 0
74
SO_BROADCAST            = 1 shl 1
75
SO_DEBUG                = 1 shl 2
76
SO_DONTROUTE            = 1 shl 3
77
SO_KEEPALIVE            = 1 shl 4
78
SO_OOBINLINE            = 1 shl 5
79
SO_REUSEADDR            = 1 shl 6
80
SO_REUSEPORT            = 1 shl 7
81
SO_USELOOPBACK          = 1 shl 8
82
SO_BINDTODEVICE         = 1 shl 9
83
 
3600 hidnplayr 84
SO_BLOCK                = 1 shl 10      ; TO BE REMOVED
3545 hidnplayr 85
SO_NONBLOCK             = 1 shl 31
86
 
87
; Socket flags for user calls
88
MSG_PEEK                = 0x02
89
MSG_DONTWAIT            = 0x40
90
 
91
; Socket level
92
SOL_SOCKET              = 0
93
 
94
 
95
; Socket States
3600 hidnplayr 96
SS_NOFDREF              = 0x0001        ; no file table ref any more
97
SS_ISCONNECTED          = 0x0002        ; socket connected to a peer
98
SS_ISCONNECTING         = 0x0004        ; in process of connecting to peer
99
SS_ISDISCONNECTING      = 0x0008        ; in process of disconnecting
100
SS_CANTSENDMORE         = 0x0010        ; can't send more data to peer
101
SS_CANTRCVMORE          = 0x0020        ; can't receive more data from peer
102
SS_RCVATMARK            = 0x0040        ; at mark on input
103
SS_ISABORTING           = 0x0080        ; aborting fd references - close()
104
SS_RESTARTSYS           = 0x0100        ; restart blocked system calls
105
SS_ISDISCONNECTED       = 0x0800        ; socket disconnected from peer
3545 hidnplayr 106
 
3600 hidnplayr 107
SS_ASYNC                = 0x0100        ; async i/o notify
108
SS_ISCONFIRMING         = 0x0200        ; deciding to accept connection req
3545 hidnplayr 109
SS_MORETOCOME           = 0x0400
110
 
111
SS_BLOCKED              = 0x8000
112
 
113
 
3600 hidnplayr 114
SOCKET_MAXDATA          = 4096*32       ; must be 4096*(power of 2) where 'power of 2' is at least 8
115
MAX_backlog             = 20            ; maximum backlog for stream sockets
3545 hidnplayr 116
 
117
; Error Codes
118
ENOBUFS                 = 55
119
ECONNREFUSED            = 61
120
ECONNRESET              = 52
121
ETIMEDOUT               = 60
122
ECONNABORTED            = 53
123
 
124
; Api protocol numbers
125
API_ETH                 = 0
126
API_IPv4                = 1
127
API_ICMP                = 2
128
API_UDP                 = 3
129
API_TCP                 = 4
130
API_ARP                 = 5
131
API_PPPOE               = 6
132
API_IPv6                = 7
133
 
3600 hidnplayr 134
; Network device types
135
NET_DEVICE_LOOPBACK     = 0
136
NET_DEVICE_ETH          = 1
137
NET_DEVICE_SLIP         = 2
138
 
139
; Network link types (link protocols)
140
NET_LINK_LOOPBACK       = 0     ;;; Really a link type?
141
NET_LINK_MAC            = 1     ; Media access control (ethernet, isdn, ...)
142
NET_LINK_PPP            = 2     ; Point to Point Protocol (PPPoE, ...)
143
NET_LINK_IEEE802.11     = 3     ; IEEE 802.11 (WiFi)
144
 
145
; Hardware acceleration bits
3545 hidnplayr 146
HWACC_TCP_IPv4          = 1 shl 0
147
 
148
struct  NET_DEVICE
149
 
3600 hidnplayr 150
        device_type     dd ?    ; Type field
3545 hidnplayr 151
        mtu             dd ?    ; Maximal Transmission Unit
152
        name            dd ?    ; Ptr to 0 terminated string
153
 
154
        unload          dd ?    ; Ptrs to driver functions
155
        reset           dd ?    ;
156
        transmit        dd ?    ;
157
 
158
        bytes_tx        dq ?    ; Statistics, updated by the driver
159
        bytes_rx        dq ?    ;
160
        packets_tx      dd ?    ;
161
        packets_rx      dd ?    ;
162
 
3600 hidnplayr 163
        link_state      dd ?    ; link state (0 = no link)
3545 hidnplayr 164
        hwacc           dd ?    ; bitmask stating enabled HW accelerations (offload engines)
165
 
166
ends
167
 
168
 
169
; Exactly as it says..
170
macro pseudo_random reg {
171
        add     reg, [esp]
172
        rol     reg, 5
173
        xor     reg, [timer_ticks]
174
;        add     reg, [CPU_FREQ]
175
        imul    reg, 214013
176
        xor     reg, 0xdeadbeef
177
        rol     reg, 9
178
}
179
 
180
; Network to Hardware byte order (dword)
181
macro ntohd reg {
182
 
183
        rol     word reg, 8
184
        rol     dword reg, 16
185
        rol     word reg , 8
186
 
187
}
188
 
189
; Network to Hardware byte order (word)
190
macro ntohw reg {
191
 
192
        rol     word reg, 8
193
 
194
}
195
 
196
 
197
include "queue.inc"
198
 
199
include "loopback.inc"
200
include "ethernet.inc"
201
 
202
include "PPPoE.inc"
203
 
204
include "ARP.inc"
205
include "IPv4.inc"
206
include "IPv6.inc"
207
 
208
include "icmp.inc"
209
include "udp.inc"
210
include "tcp.inc"
211
 
212
include "socket.inc"
213
 
214
 
215
 
216
align 4
217
uglobal
218
 
219
        NET_RUNNING     dd  ?
220
        NET_DEFAULT     dd  ?
3600 hidnplayr 221
        NET_DRV_LIST    rd  NET_DEVICES_MAX
3545 hidnplayr 222
 
223
endg
224
 
225
 
226
;-----------------------------------------------------------------
227
;
228
; stack_init
229
;
230
;  This function calls all network init procedures
231
;
232
;  IN:  /
233
;  OUT: /
234
;
235
;-----------------------------------------------------------------
236
align 4
237
stack_init:
238
 
239
; Init the network drivers list
240
        xor     eax, eax
241
        mov     edi, NET_RUNNING
3600 hidnplayr 242
        mov     ecx, (NET_DEVICES_MAX + 2)
3545 hidnplayr 243
        rep     stosd
244
 
245
        PPPoE_init
246
 
247
        IPv4_init
248
;        IPv6_init
249
        ICMP_init
250
 
251
        ARP_init
252
        UDP_init
253
        TCP_init
254
 
255
        SOCKET_init
256
 
257
        mov     [net_tmr_count], 0
258
 
259
        ret
260
 
261
 
262
 
263
; Wakeup every tick.
264
proc stack_handler_has_work?
265
 
266
        mov eax, [timer_ticks]
267
        cmp eax, [net_10ms]
268
 
269
        ret
270
endp
271
 
272
 
273
;-----------------------------------------------------------------
274
;
275
; stack_handler
276
;
277
;  This function is called in kernel loop
278
;
279
;  IN:  /
280
;  OUT: /
281
;
282
;-----------------------------------------------------------------
283
align 4
284
stack_handler:
285
 
286
        ; Test for 10ms tick
287
        mov     eax, [timer_ticks]
288
        cmp     eax, [net_10ms]
289
        je      .exit
290
        mov     [net_10ms], eax
291
 
292
        cmp     [NET_RUNNING], 0
293
        je      .exit
294
 
295
        test    [net_10ms], 0x0f        ; 160ms
296
        jnz     .exit
297
 
298
        TCP_timer_160ms
299
 
300
        test    [net_10ms], 0x3f        ; 640ms
301
        jnz     .exit
302
 
303
        TCP_timer_640ms
304
        ARP_decrease_entry_ttls
305
        IPv4_decrease_fragment_ttls
306
 
307
  .exit:
308
        ret
309
 
310
 
311
 
312
align 4
313
NET_link_changed:
314
 
3556 hidnplayr 315
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.state]
3545 hidnplayr 316
 
317
align 4
318
NET_send_event:
319
 
3556 hidnplayr 320
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_send_event\n"
3545 hidnplayr 321
 
322
; Send event to all applications
323
        push    edi ecx
324
        mov     edi, SLOT_BASE
325
        mov     ecx, [TASK_COUNT]
326
  .loop:
327
        add     edi, 256
328
        or      [edi + APPDATA.event_mask], EVENT_NETWORK2
329
        loop    .loop
330
        pop     ecx edi
331
 
332
        ret
333
 
334
 
335
 
336
;-----------------------------------------------------------------
337
;
338
; NET_add_device:
339
;
340
;  This function is called by the network drivers,
341
;  to register each running NIC to the kernel
342
;
343
;  IN:  Pointer to device structure in ebx
344
;  OUT: Device num in eax, -1 on error
345
;
346
;-----------------------------------------------------------------
347
align 4
348
NET_add_device:
349
 
3556 hidnplayr 350
        DEBUGF  DEBUG_NETWORK_VERBOSE, "NET_Add_Device: %x\n", ebx   ;;; TODO: use mutex to lock net device list
3545 hidnplayr 351
 
3600 hidnplayr 352
        cmp     [NET_RUNNING], NET_DEVICES_MAX
3545 hidnplayr 353
        jae     .error
354
 
355
;----------------------------------
356
; Check if device is already listed
357
        mov     eax, ebx
3600 hidnplayr 358
        mov     ecx, NET_DEVICES_MAX    ; We need to check whole list because a device may be removed without re-organizing list
3545 hidnplayr 359
        mov     edi, NET_DRV_LIST
360
 
361
        repne   scasd                   ; See if device is already in the list
362
        jz      .error
363
 
364
;----------------------------
365
; Find empty slot in the list
366
        xor     eax, eax
3600 hidnplayr 367
        mov     ecx, NET_DEVICES_MAX
3545 hidnplayr 368
        mov     edi, NET_DRV_LIST
369
 
370
        repne   scasd
371
        jnz     .error
372
 
373
        sub     edi, 4
374
 
375
;-----------------------------
376
; Add device to the found slot
377
        mov     [edi], ebx              ; add device to list
378
 
379
        mov     eax, edi                ; Calculate device number in eax
380
        sub     eax, NET_DRV_LIST
381
        shr     eax, 2
382
 
383
        inc     [NET_RUNNING]           ; Indicate that one more network device is up and running
384
 
385
        call    NET_send_event
386
 
3556 hidnplayr 387
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Device number: %u\n", eax
3545 hidnplayr 388
        ret
389
 
390
  .error:
391
        or      eax, -1
3556 hidnplayr 392
        DEBUGF  DEBUG_NETWORK_ERROR, "Adding network device failed\n"
3545 hidnplayr 393
        ret
394
 
395
 
396
 
397
;-----------------------------------------------------------------
398
;
399
; NET_Remove_Device:
400
;
401
;  This function is called by etwork drivers,
402
;  to unregister network devices from the kernel
403
;
404
;  IN:  Pointer to device structure in ebx
405
;  OUT: eax: -1 on error
406
;
407
;-----------------------------------------------------------------
408
align 4
409
NET_remove_device:
410
 
411
        cmp     [NET_RUNNING], 0
412
        je      .error
413
 
414
        cmp     [NET_DRV_LIST], ebx
415
        jne     @f
416
        mov     [NET_DRV_LIST], 0
417
        cmp     [NET_RUNNING], 1
418
        je      @f
419
        ; there are still active devices, find one and make it default
420
        xor     eax, eax
3600 hidnplayr 421
        mov     ecx, NET_DEVICES_MAX
3545 hidnplayr 422
        mov     edi, NET_DRV_LIST
423
        repe    scasd
424
        je      @f
425
        shr     edi, 2
426
        dec     edi
427
        mov     [NET_DEFAULT], edi
428
       @@:
429
 
430
;----------------------------
431
; Find the driver in the list
432
 
433
        mov     eax, ebx
3600 hidnplayr 434
        mov     ecx, NET_DEVICES_MAX
3545 hidnplayr 435
        mov     edi, NET_DRV_LIST+4
436
 
437
        repne   scasd
438
        jnz     .error
439
 
440
;------------------------
441
; Remove it from the list
442
 
443
        xor     eax, eax
444
        mov     dword [edi-4], eax
445
 
446
        call    NET_send_event
447
 
448
        dec     [NET_RUNNING]
449
        ret
450
 
451
  .error:
452
        or      eax, -1
453
        ret
454
 
455
 
456
 
457
;-----------------------------------------------------------------
458
;
459
; NET_ptr_to_num
460
;
461
; IN:  ebx = ptr to device struct
462
; OUT: edi = -1 on error, device number otherwise
463
;
464
;-----------------------------------------------------------------
465
align 4
466
NET_ptr_to_num:
467
        push    ecx
468
 
3600 hidnplayr 469
        mov     ecx, NET_DEVICES_MAX
3545 hidnplayr 470
        mov     edi, NET_DRV_LIST
471
 
472
  .loop:
473
        cmp     ebx, [edi]
474
        jz      .found
475
        add     edi, 4
476
        dec     ecx
477
        jnz     .loop
478
 
479
        ; repnz  scasd could work too if eax is used instead of ebx!
480
 
481
        or      edi, -1
482
 
483
        pop     ecx
484
        ret
485
 
486
  .found:
487
        sub     edi, NET_DRV_LIST
488
        shr     edi, 2
489
 
490
        pop     ecx
491
        ret
492
 
493
;-----------------------------------------------------------------
494
;
495
; checksum_1
496
;
497
;  This is the first of two functions needed to calculate a checksum.
498
;
499
;  IN:  edx = start offset for semi-checksum
500
;       esi = pointer to data
501
;       ecx = data size
502
;  OUT: edx = semi-checksum
503
;
504
;
505
; Code was optimized by diamond
506
;
507
;-----------------------------------------------------------------
508
align 4
509
checksum_1:
510
 
511
        shr     ecx, 1
512
        pushf
513
        jz      .no_2
514
 
515
        shr     ecx, 1
516
        pushf
517
        jz      .no_4
518
 
519
        shr     ecx, 1
520
        pushf
521
        jz      .no_8
522
 
523
  .loop:
524
        add     dl, [esi+1]
525
        adc     dh, [esi+0]
526
 
527
        adc     dl, [esi+3]
528
        adc     dh, [esi+2]
529
 
530
        adc     dl, [esi+5]
531
        adc     dh, [esi+4]
532
 
533
        adc     dl, [esi+7]
534
        adc     dh, [esi+6]
535
 
536
        adc     edx, 0
537
        add     esi, 8
538
 
539
        dec     ecx
540
        jnz     .loop
541
 
542
        adc     edx, 0
543
 
544
  .no_8:
545
        popf
546
        jnc     .no_4
547
 
548
        add     dl, [esi+1]
549
        adc     dh, [esi+0]
550
 
551
        adc     dl, [esi+3]
552
        adc     dh, [esi+2]
553
 
554
        adc     edx, 0
555
        add     esi, 4
556
 
557
  .no_4:
558
        popf
559
        jnc     .no_2
560
 
561
        add     dl, [esi+1]
562
        adc     dh, [esi+0]
563
 
564
        adc     edx, 0
565
        inc     esi
566
        inc     esi
567
 
568
  .no_2:
569
        popf
570
        jnc     .end
571
 
572
        add     dh, [esi+0]
573
        adc     edx, 0
574
  .end:
575
        ret
576
 
577
;-----------------------------------------------------------------
578
;
579
; checksum_2
580
;
581
;  This function calculates the final ip/tcp/udp checksum for you
582
;
583
;  IN:  edx = semi-checksum
584
;  OUT: dx = checksum (in INET byte order)
585
;
586
;-----------------------------------------------------------------
587
align 4
588
checksum_2:
589
 
590
        mov     ecx, edx
591
        shr     ecx, 16
592
        and     edx, 0xffff
593
        add     edx, ecx
594
 
595
        mov     ecx, edx
596
        shr     ecx, 16
597
        add     dx, cx
598
        test    dx, dx          ; it seems that ZF is not set when CF is set :(
599
        not     dx
600
        jnz     .not_zero
601
        dec     dx
602
  .not_zero:
603
        xchg    dl, dh
604
 
3556 hidnplayr 605
        DEBUGF  DEBUG_NETWORK_VERBOSE, "Checksum: %x\n", dx
3545 hidnplayr 606
 
607
        ret
608
 
609
 
610
 
611
;----------------------------------------------------------------
612
;
613
;  System function to work with network devices (75)
614
;
615
;----------------------------------------------------------------
616
align 4
617
sys_network:                    ; FIXME: make default device easily accessible
618
 
619
        cmp     ebx, -1
620
        jne     @f
621
 
622
        mov     eax, [NET_RUNNING]
623
        jmp     .return
624
 
625
   @@:
3600 hidnplayr 626
        cmp     bh, NET_DEVICES_MAX             ; Check if device number exists
3545 hidnplayr 627
        jae     .doesnt_exist
628
 
629
        mov     esi, ebx
630
        and     esi, 0x0000ff00
631
        shr     esi, 6
632
 
633
        cmp     dword [esi + NET_DRV_LIST], 0   ; check if driver is running
634
        je      .doesnt_exist
635
 
636
        mov     eax, [esi + NET_DRV_LIST]
637
 
638
        and     ebx, 0x000000ff
639
        cmp     ebx, .number
640
        ja      .doesnt_exist
641
        jmp     dword [.table + 4*ebx]
642
 
643
  .table:
644
        dd      .get_type               ; 0
645
        dd      .get_dev_name           ; 1
646
        dd      .reset                  ; 2
647
        dd      .stop                   ; 3
648
        dd      .get_ptr                ; 4
649
        dd      .get_drv_name           ; 5
650
  .number = ($ - .table) / 4 - 1
651
 
652
  .get_type:                            ; 0 = Get device type (ethernet/token ring/...)
653
 
3600 hidnplayr 654
        mov     eax, [eax + NET_DEVICE.device_type]
3545 hidnplayr 655
        jmp     .return
656
 
657
 
658
  .get_dev_name:                        ; 1 = Get device name
659
 
660
        mov     esi, [eax + NET_DEVICE.name]
661
        mov     edi, ecx
662
 
663
        mov     ecx, 64/4 ; max length
664
        rep     movsd
665
 
666
        xor     eax, eax
667
        jmp     .return
668
 
669
  .reset:                               ; 2 = Reset the device
670
 
671
        call    [eax + NET_DEVICE.reset]
672
        jmp     .return
673
 
674
  .stop:                                ; 3 = Stop driver for this device
675
 
676
        call    [eax + NET_DEVICE.unload]
677
        jmp     .return
678
 
679
 
680
  .get_ptr:                             ; 4 = Get driver pointer
681
 
682
        jmp     .return
683
 
684
 
685
  .get_drv_name:                        ; 5 = Get driver name
686
 
687
        xor     eax, eax
688
        jmp     .return
689
 
690
 
691
  .doesnt_exist:
692
        mov     eax, -1
693
 
694
  .return:
695
        mov     [esp+32], eax
696
        ret
697
 
698
 
699
;----------------------------------------------------------------
700
;
701
;  System function to work with protocols  (76)
702
;
703
;----------------------------------------------------------------
704
align 4
705
sys_protocols:
3600 hidnplayr 706
        cmp     bh, NET_DEVICES_MAX             ; Check if device number exists
3545 hidnplayr 707
        jae     .doesnt_exist
708
 
709
        mov     esi, ebx
710
        and     esi, 0x0000ff00
711
        shr     esi, 6                          ; now we have the device num * 4 in esi
712
        cmp     [esi + NET_DRV_LIST], 0         ; check if driver is running
713
        je      .doesnt_exist
714
 
715
        push    .return                         ; return address (we will be using jumps instead of calls)
716
 
717
        mov     eax, ebx                        ; set ax to protocol number
718
        shr     eax, 16                         ;
719
 
720
        cmp     ax, API_ETH
721
        je      ETH_api
722
 
723
        cmp     ax, API_IPv4
724
        je      IPv4_api
725
 
726
        cmp     ax, API_ICMP
727
        je      ICMP_api
728
 
729
        cmp     ax, API_UDP
730
        je      UDP_api
731
 
732
        cmp     ax, API_TCP
733
        je      TCP_api
734
 
735
        cmp     ax, API_ARP
736
        je      ARP_api
737
 
738
        cmp     ax, API_PPPOE
739
        je      PPPoE_api
740
 
741
        cmp     ax, API_IPv6
742
        je      IPv6_api
743
 
744
        add     esp, 4                           ; if we reached here, no function was called, so we need to balance stack
745
 
746
  .doesnt_exist:
747
        mov     eax, -1
748
 
749
  .return:
750
        mov     [esp+28+4], eax                 ; return eax value to the program
751
        ret