Subversion Repositories Kolibri OS

Rev

Rev 1508 | Rev 1687 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 1599 $
  9.  
  10.  
  11. align 4
  12. proc alloc_page
  13.  
  14.            pushfd
  15.            cli
  16.            push ebx
  17. ;//-
  18.            cmp [pg_data.pages_free], 1
  19.            jle .out_of_memory
  20. ;//-
  21.  
  22.            mov ebx, [page_start]
  23.            mov ecx, [page_end]
  24. .l1:
  25.            bsf eax,[ebx];
  26.            jnz .found
  27.            add ebx,4
  28.            cmp ebx, ecx
  29.            jb .l1
  30.            pop ebx
  31.            popfd
  32.            xor eax,eax
  33.            ret
  34. .found:
  35. ;//-
  36.            dec [pg_data.pages_free]
  37.            jz .out_of_memory
  38. ;//-
  39.            btr [ebx], eax
  40.            mov [page_start],ebx
  41.            sub ebx, sys_pgmap
  42.            lea eax, [eax+ebx*8]
  43.            shl eax, 12
  44. ;//-       dec [pg_data.pages_free]
  45.            pop ebx
  46.            popfd
  47.            ret
  48. ;//-
  49. .out_of_memory:
  50.            mov [pg_data.pages_free], 1
  51.            xor eax, eax
  52.            pop ebx
  53.            popfd
  54.            ret
  55. ;//-
  56. endp
  57.  
  58. align 4
  59. proc alloc_pages stdcall, count:dword
  60.            pushfd
  61.            push ebx
  62.            push edi
  63.            cli
  64.            mov eax, [count]
  65.            add eax, 7
  66.            shr eax, 3
  67.            mov [count], eax
  68. ;//-
  69.            mov ebx, [pg_data.pages_free]
  70.            sub  ebx, 9
  71.            js .out_of_memory
  72.            shr   ebx, 3
  73.            cmp eax, ebx
  74.            jg .out_of_memory
  75. ;//-
  76.            mov ecx, [page_start]
  77.            mov ebx, [page_end]
  78. .find:
  79.            mov edx, [count]
  80.            mov edi, ecx
  81. .match:
  82.            cmp byte [ecx], 0xFF
  83.            jne .next
  84.            dec edx
  85.            jz .ok
  86.            inc ecx
  87.            cmp ecx,ebx
  88.            jb .match
  89. .out_of_memory:
  90. .fail:
  91.            xor eax, eax
  92.            pop edi
  93.            pop ebx
  94.            popfd
  95.            ret
  96. .next:
  97.            inc ecx
  98.            cmp ecx, ebx
  99.            jb .find
  100.            pop edi
  101.            pop ebx
  102.            popfd
  103.            xor eax, eax
  104.            ret
  105. .ok:
  106.            sub ecx, edi
  107.            inc ecx
  108.            push esi
  109.            mov esi, edi
  110.            xor eax, eax
  111.            rep stosb
  112.            sub esi, sys_pgmap
  113.            shl esi, 3+12
  114.            mov eax, esi
  115.            mov ebx, [count]
  116.            shl ebx, 3
  117.            sub [pg_data.pages_free], ebx
  118.            pop esi
  119.            pop edi
  120.            pop ebx
  121.            popfd
  122.            ret
  123. endp
  124.  
  125. align 4
  126. proc map_page stdcall,lin_addr:dword,phis_addr:dword,flags:dword
  127.            push ebx
  128.            mov eax, [phis_addr]
  129.            and eax, not 0xFFF
  130.            or eax, [flags]
  131.            mov ebx, [lin_addr]
  132.            shr ebx, 12
  133.            mov [page_tabs+ebx*4], eax
  134.            mov eax, [lin_addr]
  135.            invlpg [eax]
  136.            pop ebx
  137.            ret
  138. endp
  139.  
  140. align 4
  141. map_space:    ;not implemented
  142.  
  143.  
  144.            ret
  145.  
  146.  
  147. align 4
  148. proc free_page
  149. ;arg:  eax  page address
  150.            pushfd
  151.            cli
  152.            shr eax, 12                        ;page index
  153.            bts dword [sys_pgmap], eax         ;that's all!
  154.            cmc
  155.            adc [pg_data.pages_free], 0
  156.            shr eax, 3
  157.            and eax, not 3                     ;dword offset from page_map
  158.            add eax, sys_pgmap
  159.            cmp [page_start], eax
  160.            ja @f
  161.            popfd
  162.            ret
  163. @@:
  164.            mov [page_start], eax
  165.            popfd
  166.            ret
  167. endp
  168.  
  169. proc map_io_mem stdcall, base:dword, size:dword, flags:dword
  170.  
  171.            push ebx
  172.            push edi
  173.            mov eax, [size]
  174.            add eax, 4095
  175.            and eax, -4096
  176.            mov [size], eax
  177.            stdcall alloc_kernel_space, eax
  178.            test eax, eax
  179.            jz .fail
  180.            push eax
  181.  
  182.            mov edi, 0x1000
  183.            mov ebx, eax
  184.            mov ecx,[size]
  185.            mov edx, [base]
  186.            shr eax, 12
  187.            shr ecx, 12
  188.            and edx, -4096
  189.            or edx, [flags]
  190. @@:
  191.            mov [page_tabs+eax*4], edx
  192.           ; push eax
  193.            invlpg [ebx]
  194.           ; pop eax
  195.            inc eax
  196.            add ebx, edi
  197.            add edx, edi
  198.            loop @B
  199.  
  200.            pop eax
  201.            mov edx, [base]
  202.            and edx, 4095
  203.            add eax, edx
  204. .fail:
  205.            pop edi
  206.            pop ebx
  207.            ret
  208. endp
  209.  
  210. ; param
  211. ;  eax= page base + page flags
  212. ;  ebx= linear address
  213. ;  ecx= count
  214.  
  215. align 4
  216. commit_pages:
  217.            push edi
  218.            test ecx, ecx
  219.            jz .fail
  220.  
  221.            mov edi, ebx
  222.            mov ebx, pg_data.pg_mutex
  223.            call wait_mutex      ;ebx
  224.  
  225.            mov edx, 0x1000
  226.            mov ebx, edi
  227.            shr ebx, 12
  228. @@:
  229.            mov [page_tabs+ebx*4], eax
  230.           ; push eax
  231.            invlpg [edi]
  232.           ; pop eax
  233.            add edi, edx
  234.            add eax, edx
  235.            inc ebx
  236.            dec ecx
  237.            jnz @B
  238.            mov [pg_data.pg_mutex],ecx
  239. .fail:
  240.            pop edi
  241.            ret
  242.  
  243.  
  244. ; param
  245. ;  eax= base
  246. ;  ecx= count
  247.  
  248. align 4
  249. release_pages:
  250.  
  251.            pushad
  252.            mov ebx, pg_data.pg_mutex
  253.            call wait_mutex      ;ebx
  254.  
  255.            mov esi, eax
  256.            mov edi, eax
  257.  
  258.            shr esi, 10
  259.            add esi, page_tabs
  260.  
  261.            mov ebp, [pg_data.pages_free]
  262.            mov ebx, [page_start]
  263.            mov edx, sys_pgmap
  264. @@:
  265.            xor eax, eax
  266.            xchg eax, [esi]
  267.            push eax
  268.            invlpg [edi]
  269.            pop eax
  270.  
  271.            test eax, 1
  272.            jz .next
  273.  
  274.            shr eax, 12
  275.            bts [edx], eax
  276.            cmc
  277.            adc ebp, 0
  278.            shr eax, 3
  279.            and eax, -4
  280.            add eax, edx
  281.            cmp eax, ebx
  282.            jae .next
  283.  
  284.            mov ebx, eax
  285. .next:
  286.            add edi, 0x1000
  287.            add esi, 4
  288.            dec ecx
  289.            jnz @B
  290.            mov [pg_data.pages_free], ebp
  291.            and [pg_data.pg_mutex],0
  292.            popad
  293.            ret
  294.  
  295. ; param
  296. ;  eax= base
  297. ;  ecx= count
  298.  
  299. align 4
  300. unmap_pages:
  301.  
  302.            push edi
  303.  
  304.            mov edi, eax
  305.            mov edx, eax
  306.  
  307.            shr edi, 10
  308.            add edi, page_tabs
  309.  
  310.            xor eax, eax
  311. @@:
  312.            stosd
  313.            invlpg [edx]
  314.            add edx, 0x1000
  315.            loop @b
  316.  
  317.            pop edi
  318.            ret
  319.  
  320.  
  321. align 4
  322. proc map_page_table stdcall, lin_addr:dword, phis_addr:dword
  323.            push ebx
  324.            mov ebx, [lin_addr]
  325.            shr ebx, 22
  326.            mov eax, [phis_addr]
  327.            and eax, not 0xFFF
  328.            or eax, PG_UW          ;+PG_NOCACHE
  329.            mov dword [master_tab+ebx*4], eax
  330.            mov eax, [lin_addr]
  331.            shr eax, 10
  332.            add eax, page_tabs
  333.            invlpg [eax]
  334.            pop ebx
  335.            ret
  336. endp
  337.  
  338. align 4
  339. proc init_LFB
  340. ;           cmp dword [LFBAddress], -1
  341. ;           jne @f
  342. ;
  343. ;        mov     esi, boot_framebuf
  344. ;        call    boot_log
  345. ;
  346. ;           mov [BOOT_VAR+0x901c],byte 2
  347. ;           stdcall alloc_pages, (0x280000 / 4096)
  348. ;
  349. ;           push eax
  350. ;           call alloc_page
  351. ;           stdcall map_page_table, LFB_BASE, eax
  352. ;           pop eax
  353. ;           or eax, PG_UW
  354. ;           mov ebx, LFB_BASE
  355. ;           mov ecx, 0x280000 / 4096
  356. ;           call commit_pages
  357. ;           mov [LFBAddress], dword LFB_BASE
  358. ;           ret
  359. ;@@:
  360.            call init_mtrr
  361.  
  362.            mov edx, LFB_BASE
  363.            mov esi, [LFBAddress]
  364.            mov edi, 0x00C00000               ; 12Mb
  365.            mov dword [exp_lfb+4], edx
  366.  
  367.            shr edi, 12                       ; C00
  368. ;           mov [pg_count], edi
  369.            shr edi, 10                       ; 3
  370.  
  371.            or esi,  PG_GLOBAL+PG_LARGE+PG_UW
  372.            mov edx, sys_pgdir+(LFB_BASE shr 20)
  373. @@:
  374.            mov [edx], esi
  375.            add edx, 4
  376.            add esi, 0x00400000
  377.            dec edi
  378.            jnz @B
  379.  
  380.            mov dword [LFBAddress], LFB_BASE
  381.            mov eax, cr3       ;flush TLB
  382.            mov cr3, eax
  383.            ret
  384. endp
  385.  
  386. align 4
  387. init_userDMA:
  388.            stdcall alloc_pages, 4096    ; 16M <<<<<<<<<<+++++++++++++++++++++++++++++++++
  389.            add eax, 0x007FFFF0          ; terrible mess, sorry ...
  390.            and eax, 0xFF800000          ; align at 8M boundary
  391.            mov [UserDMAaddr], eax
  392.            or  eax, PG_LARGE + PG_UW + PG_NOCACHE
  393.            mov ebx, sys_pgdir + (USER_DMA_BUFFER shr 20)
  394.            mov [ebx], eax
  395.            add ebx, 4
  396.            add eax, 0x00400000
  397.            mov [ebx], eax
  398.            mov eax, cr3       ;flush TLB
  399.            mov cr3, eax
  400.            ret
  401.  
  402. align 4
  403. proc new_mem_resize stdcall, new_size:dword
  404.  
  405.            mov ebx, pg_data.pg_mutex
  406.            call wait_mutex    ;ebx
  407.  
  408.            mov edi, [new_size]
  409.            add edi,4095
  410.            and edi,not 4095
  411.            mov [new_size], edi
  412.  
  413.            mov edx,[current_slot]
  414.            cmp [edx+APPDATA.heap_base],0
  415.            jne .exit
  416.  
  417.            mov esi, [edx+APPDATA.mem_size]
  418.            add esi, 4095
  419.            and esi, not 4095
  420.  
  421.            cmp edi, esi
  422.            jae .expand
  423.  
  424.            shr edi, 12
  425.            shr esi, 12
  426. @@:
  427.            mov eax, [app_page_tabs+edi*4]
  428.            test eax, 1
  429.            jz .next
  430.            mov dword [app_page_tabs+edi*4], 2
  431.            mov ebx, edi
  432.            shl ebx, 12
  433.            push eax
  434.            invlpg [ebx]
  435.            pop eax
  436.            call free_page
  437.  
  438. .next:     add edi, 1
  439.            cmp edi, esi
  440.            jb @B
  441.  
  442. .update_size:
  443.            mov     ebx, [new_size]
  444.            call    update_mem_size
  445.  
  446.            xor eax, eax
  447.            dec [pg_data.pg_mutex]
  448.            ret
  449. .expand:
  450.  
  451.            push esi
  452.            push edi
  453.  
  454.            add edi, 0x3FFFFF
  455.            and edi, not(0x3FFFFF)
  456.            add esi, 0x3FFFFF
  457.            and esi, not(0x3FFFFF)
  458.  
  459.            cmp esi, edi
  460.            jae .grow
  461.  
  462.            xchg esi, edi
  463.  
  464. @@:
  465.            call alloc_page
  466.            test eax, eax
  467.            jz .exit_pop
  468.  
  469.            stdcall map_page_table, edi, eax
  470.  
  471.            push edi
  472.            shr edi, 10
  473.            add edi, page_tabs
  474.            mov ecx, 1024
  475.            xor eax, eax
  476.            cld
  477.            rep stosd
  478.            pop edi
  479.  
  480.            add edi, 0x00400000
  481.            cmp edi, esi
  482.            jb @B
  483. .grow:
  484. ;//-
  485.            pop edi
  486.            push edi
  487.            mov esi, [pg_data.pages_free]
  488.            sub esi, 1
  489.            shr edi, 12
  490.            cmp esi, edi
  491.            jle .out_of_memory
  492. ;//-
  493.            pop edi
  494.            pop esi
  495. @@:
  496.            call alloc_page
  497.            test eax, eax
  498.            jz .exit
  499.            stdcall map_page,esi,eax,dword PG_UW
  500.  
  501.            push edi
  502.            mov edi, esi
  503.            xor eax, eax
  504.            mov ecx, 1024
  505.            cld
  506.            rep stosd
  507.            pop edi
  508.  
  509.            add esi, 0x1000
  510.            cmp esi, edi
  511.            jb  @B
  512.  
  513.            jmp .update_size
  514. ;//-
  515. .exit_pop:
  516. .out_of_memory:
  517. ;//-
  518.            pop edi
  519.            pop esi
  520. .exit:
  521.            xor eax, eax
  522.            inc eax
  523.            dec [pg_data.pg_mutex]
  524.            ret
  525. endp
  526.  
  527. update_mem_size:
  528. ; in: edx = slot base
  529. ;     ebx = new memory size
  530. ; destroys eax,ecx,edx
  531.  
  532.            mov    [APPDATA.mem_size+edx],ebx
  533. ;search threads and update
  534. ;application memory size infomation
  535.            mov    ecx,[APPDATA.dir_table+edx]
  536.            mov    eax,2
  537.  
  538. .search_threads:
  539. ;eax = current slot
  540. ;ebx = new memory size
  541. ;ecx = page directory
  542.            cmp    eax,[TASK_COUNT]
  543.            jg     .search_threads_end
  544.            mov    edx,eax
  545.            shl    edx,5
  546.            cmp    word [CURRENT_TASK+edx+TASKDATA.state],9 ;if slot empty?
  547.            jz     .search_threads_next
  548.            shl    edx,3
  549.            cmp    [SLOT_BASE+edx+APPDATA.dir_table],ecx     ;if it is our thread?
  550.            jnz    .search_threads_next
  551.            mov    [SLOT_BASE+edx+APPDATA.mem_size],ebx     ;update memory size
  552. .search_threads_next:
  553.            inc    eax
  554.            jmp    .search_threads
  555. .search_threads_end:
  556.            ret
  557.  
  558. ; param
  559. ;  eax= linear address
  560. ;
  561. ; retval
  562. ;  eax= phisical page address
  563.  
  564. align 4
  565. get_pg_addr:
  566.            shr eax, 12
  567.            mov eax, [page_tabs+eax*4]
  568.            and eax, 0xFFFFF000
  569.            ret
  570.  
  571.  
  572. align 4
  573. ; Now it is called from core/sys32::exc_c (see stack frame there)
  574. proc page_fault_handler
  575.  
  576.     .err_addr   equ ebp-4
  577.  
  578.         push    ebx               ;save exception number (#PF)
  579.         mov     ebp, esp
  580.         mov     ebx, cr2
  581.         push    ebx               ;that is locals: .err_addr = cr2
  582.         inc     [pg_data.pages_faults]
  583.  
  584.         mov     eax, [pf_err_code]
  585.  
  586.         cmp     ebx, OS_BASE      ;ebx == .err_addr
  587.         jb      .user_space       ;ñòðàíèöà â ïàìÿòè ïðèëîæåíèÿ ;
  588.  
  589.         cmp     ebx, page_tabs
  590.         jb      .kernel_space     ;ñòðàíèöà â ïàìÿòè ÿäðà
  591.  
  592.         cmp     ebx, kernel_tabs
  593.         jb      .alloc;.app_tabs  ;òàáëèöû ñòðàíèö ïðèëîæåíèÿ ;
  594.                                   ;ïðîñòî ñîçäàäèì îäíó
  595. if 0 ;ïîêà ýòî ïðîñòî ëèøíåå
  596.         cmp     ebx, LFB_BASE
  597.         jb      .core_tabs        ;òàáëèöû ñòðàíèö ÿäðà
  598.                                   ;Îøèáêà
  599.   .lfb:
  600.                                   ;îáëàñòü LFB
  601.                                   ;Îøèáêà
  602.         jmp     .fail
  603. end if
  604. .core_tabs:
  605. .fail:  ;simply return to caller
  606.         mov     esp, ebp
  607.         pop     ebx               ;restore exception number (#PF)
  608.         ret
  609.  
  610. ;        xchg bx, bx
  611. ;        add     esp,12 ;clear in stack: locals(.err_addr) + #PF + ret_to_caller
  612. ;        restore_ring3_context
  613. ;        iretd
  614.  
  615. .user_space:
  616.         test    eax, PG_MAP
  617.         jnz     .err_access       ;Ñòðàíèöà ïðèñóòñòâóåò
  618.                                   ;Îøèáêà äîñòóïà ?
  619.  
  620.         shr     ebx, 12
  621.         mov     ecx, ebx
  622.         shr     ecx, 10
  623.         mov     edx, [master_tab+ecx*4]
  624.         test    edx, PG_MAP
  625.         jz      .fail             ;òàáëèöà ñòðàíèö íå ñîçäàíà
  626.                                   ;íåâåðíûé àäðåñ â ïðîãðàììå
  627.  
  628.         mov     eax, [page_tabs+ebx*4]
  629.         test    eax, 2
  630.         jz      .fail             ;àäðåñ íå çàðåçåðâèðîâàí äëÿ ;
  631.                                   ;èñïîëüçîâàíèÿ. Îøèáêà
  632. .alloc:
  633.         call    alloc_page
  634.         test    eax, eax
  635.         jz      .fail
  636.  
  637.         stdcall map_page,[.err_addr],eax,PG_UW
  638.  
  639.         mov     edi, [.err_addr]
  640.         and     edi, 0xFFFFF000
  641.         mov     ecx, 1024
  642.         xor     eax, eax
  643.        ;cld     ;caller is duty for this
  644.         rep     stosd
  645. .exit:  ;iret with repeat fault instruction
  646.         add     esp,12 ;clear in stack: locals(.err_addr) + #PF + ret_to_caller
  647.         restore_ring3_context
  648.         iretd
  649.  
  650. .err_access:
  651. ; access denied? this may be a result of copy-on-write protection for DLL
  652. ; check list of HDLLs
  653.         and     ebx, not 0xFFF
  654.         mov     eax, [CURRENT_TASK]
  655.         shl     eax, 8
  656.         mov     eax, [SLOT_BASE+eax+APPDATA.dlls_list_ptr]
  657.         test    eax, eax
  658.         jz      .fail
  659.         mov     esi, [eax+HDLL.fd]
  660. .scan_hdll:
  661.         cmp     esi, eax
  662.         jz      .fail
  663.         mov     edx, ebx
  664.         sub     edx, [esi+HDLL.base]
  665.         cmp     edx, [esi+HDLL.size]
  666.         jb      .fault_in_hdll
  667. .scan_hdll.next:
  668.         mov     esi, [esi+HDLL.fd]
  669.         jmp     .scan_hdll
  670. .fault_in_hdll:
  671. ; allocate new page, map it as rw and copy data
  672.         call    alloc_page
  673.         test    eax, eax
  674.         jz      .fail
  675.         stdcall map_page,ebx,eax,PG_UW
  676.         mov     edi, ebx
  677.         mov     ecx, 1024
  678.         sub     ebx, [esi+HDLL.base]
  679.         mov     esi, [esi+HDLL.parent]
  680.         mov     esi, [esi+DLLDESCR.data]
  681.         add     esi, ebx
  682.         rep     movsd
  683.         jmp     .exit
  684.  
  685. .kernel_space:
  686.         test    eax, PG_MAP
  687.         jz      .fail   ;ñòðàíèöà íå ïðèñóòñòâóåò
  688.  
  689.         test    eax,12  ;U/S (+below)
  690.         jnz     .fail   ;ïðèëîæåíèå îáðàòèëîñü ê ïàìÿòè
  691.                         ;ÿäðà
  692.        ;test    eax, 8
  693.        ;jnz     .fail   ;óñòàíîâëåí çàðåçåðâèðîâàííûé áèò
  694.                         ;â òàáëèöàõ ñòðàíèö. äîáàâëåíî â P4/Xeon
  695.  
  696. ;ïîïûòêà çàïèñè â çàùèù¸ííóþ ñòðàíèöó ÿäðà
  697.  
  698.         cmp     ebx, tss._io_map_0
  699.         jb      .fail
  700.  
  701.         cmp     ebx, tss._io_map_0+8192
  702.         jae     .fail
  703.  
  704. ; io permission map
  705. ; copy-on-write protection
  706.  
  707.         call    alloc_page
  708.         test    eax, eax
  709.         jz      .fail
  710.  
  711.         push    eax
  712.         stdcall map_page,[.err_addr],eax,dword PG_SW
  713.         pop     eax
  714.         mov     edi, [.err_addr]
  715.         and     edi, -4096
  716.         lea     esi, [edi+(not tss._io_map_0)+1]; -tss._io_map_0
  717.  
  718.         mov     ebx, esi
  719.         shr     ebx, 12
  720.         mov     edx, [current_slot]
  721.         or      eax, PG_SW
  722.         mov     [edx+APPDATA.io_map+ebx*4], eax
  723.  
  724.         add     esi, [default_io_map]
  725.         mov     ecx, 4096/4
  726.        ;cld     ;caller is duty for this
  727.         rep     movsd
  728.         jmp     .exit
  729. endp
  730.  
  731. ; returns number of mapped bytes
  732. proc map_mem stdcall, lin_addr:dword,slot:dword,\
  733.                       ofs:dword,buf_size:dword,req_access:dword
  734.            push 0 ; initialize number of mapped bytes
  735.  
  736.            cmp [buf_size], 0
  737.            jz .exit
  738.  
  739.            mov eax, [slot]
  740.            shl eax, 8
  741.            mov eax, [SLOT_BASE+eax+APPDATA.dir_table]
  742.            and eax, 0xFFFFF000
  743.  
  744.            stdcall map_page,[ipc_pdir],eax,PG_UW
  745.            mov ebx, [ofs]
  746.            shr ebx, 22
  747.            mov esi, [ipc_pdir]
  748.            mov edi, [ipc_ptab]
  749.            mov eax, [esi+ebx*4]
  750.            and eax, 0xFFFFF000
  751.            jz .exit
  752.            stdcall map_page,edi,eax,PG_UW
  753. ;           inc ebx
  754. ;           add edi, 0x1000
  755. ;           mov eax, [esi+ebx*4]
  756. ;           test eax, eax
  757. ;           jz @f
  758. ;          and eax, 0xFFFFF000
  759. ;           stdcall map_page, edi, eax
  760.  
  761. @@:        mov edi, [lin_addr]
  762.            and edi, 0xFFFFF000
  763.            mov ecx, [buf_size]
  764.            add ecx, 4095
  765.            shr ecx, 12
  766.            inc ecx
  767.  
  768.            mov edx, [ofs]
  769.            shr edx, 12
  770.            and edx, 0x3FF
  771.            mov esi, [ipc_ptab]
  772.  
  773. .map:
  774.            stdcall safe_map_page,[slot],[req_access],[ofs]
  775.            jnc .exit
  776.            add dword [ebp-4], 4096
  777.            add [ofs], 4096
  778.            dec ecx
  779.            jz  .exit
  780.            add edi, 0x1000
  781.            inc edx
  782.            cmp edx, 0x400
  783.            jnz .map
  784.            inc ebx
  785.            mov eax, [ipc_pdir]
  786.            mov eax, [eax+ebx*4]
  787.            and eax, 0xFFFFF000
  788.            jz  .exit
  789.            stdcall map_page,esi,eax,PG_UW
  790.            xor edx, edx
  791.            jmp .map
  792.  
  793. .exit:
  794.            pop eax
  795.            ret
  796. endp
  797.  
  798. proc map_memEx stdcall, lin_addr:dword,slot:dword,\
  799.                         ofs:dword,buf_size:dword,req_access:dword
  800.            push 0 ; initialize number of mapped bytes
  801.  
  802.            cmp [buf_size], 0
  803.            jz .exit
  804.  
  805.            mov eax, [slot]
  806.            shl eax, 8
  807.            mov eax, [SLOT_BASE+eax+APPDATA.dir_table]
  808.            and eax, 0xFFFFF000
  809.  
  810.            stdcall map_page,[proc_mem_pdir],eax,PG_UW
  811.            mov ebx, [ofs]
  812.            shr ebx, 22
  813.            mov esi, [proc_mem_pdir]
  814.            mov edi, [proc_mem_tab]
  815.            mov eax, [esi+ebx*4]
  816.            and eax, 0xFFFFF000
  817.            test eax, eax
  818.            jz .exit
  819.            stdcall map_page,edi,eax,PG_UW
  820.  
  821. @@:        mov edi, [lin_addr]
  822.            and edi, 0xFFFFF000
  823.            mov ecx, [buf_size]
  824.            add ecx, 4095
  825.            shr ecx, 12
  826.            inc ecx
  827.  
  828.            mov edx, [ofs]
  829.            shr edx, 12
  830.            and edx, 0x3FF
  831.            mov esi, [proc_mem_tab]
  832.  
  833. .map:
  834.            stdcall safe_map_page,[slot],[req_access],[ofs]
  835.            jnc .exit
  836.            add dword [ebp-4], 0x1000
  837.            add edi, 0x1000
  838.            add [ofs], 0x1000
  839.            inc edx
  840.            dec ecx
  841.            jnz .map
  842. .exit:
  843.            pop eax
  844.            ret
  845. endp
  846.  
  847. ; in: esi+edx*4 = pointer to page table entry
  848. ; in: [slot], [req_access], [ofs] on the stack
  849. ; in: edi = linear address to map
  850. ; out: CF cleared <=> failed
  851. ; destroys: only eax
  852. proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword
  853.         mov     eax, [esi+edx*4]
  854.         test    al, PG_MAP
  855.         jz      .not_present
  856.         test    al, PG_WRITE
  857.         jz      .resolve_readonly
  858. ; normal case: writable page, just map with requested access
  859. .map:
  860.         stdcall map_page, edi, eax, [req_access]
  861.         stc
  862. .fail:
  863.         ret
  864. .not_present:
  865. ; check for alloc-on-demand page
  866.         test    al, 2
  867.         jz      .fail
  868. ; allocate new page, save it to source page table
  869.         push    ecx
  870.         call    alloc_page
  871.         pop     ecx
  872.         test    eax, eax
  873.         jz      .fail
  874.         or      al, PG_UW
  875.         mov     [esi+edx*4], eax
  876.         jmp     .map
  877. .resolve_readonly:
  878. ; readonly page, probably copy-on-write
  879. ; check: readonly request of readonly page is ok
  880.         test    [req_access], PG_WRITE
  881.         jz      .map
  882. ; find control structure for this page
  883.         pushf
  884.         cli
  885.         cld
  886.         push    ebx ecx
  887.         mov     eax, [slot]
  888.         shl     eax, 8
  889.         mov     eax, [SLOT_BASE+eax+APPDATA.dlls_list_ptr]
  890.         test    eax, eax
  891.         jz      .no_hdll
  892.         mov     ecx, [eax+HDLL.fd]
  893. .scan_hdll:
  894.         cmp     ecx, eax
  895.         jz      .no_hdll
  896.         mov     ebx, [ofs]
  897.         and     ebx, not 0xFFF
  898.         sub     ebx, [ecx+HDLL.base]
  899.         cmp     ebx, [ecx+HDLL.size]
  900.         jb      .hdll_found
  901.         mov     ecx, [ecx+HDLL.fd]
  902.         jmp     .scan_hdll
  903. .no_hdll:
  904.         pop     ecx ebx
  905.         popf
  906.         clc
  907.         ret
  908. .hdll_found:
  909. ; allocate page, save it in page table, map it, copy contents from base
  910.         mov     eax, [ecx+HDLL.parent]
  911.         add     ebx, [eax+DLLDESCR.data]
  912.         call    alloc_page
  913.         test    eax, eax
  914.         jz      .no_hdll
  915.         or      al, PG_UW
  916.         mov     [esi+edx*4], eax
  917.         stdcall map_page, edi, eax, [req_access]
  918.         push    esi edi
  919.         mov     esi, ebx
  920.         mov     ecx, 4096/4
  921.         rep     movsd
  922.         pop     edi esi
  923.         pop     ecx ebx
  924.         popf
  925.         stc
  926.         ret
  927. endp
  928.  
  929. sys_IPC:
  930. ;input:
  931. ;  ebx=1 - set ipc buffer area
  932. ;    ecx=address of buffer
  933. ;    edx=size of buffer
  934. ;  eax=2 - send message
  935. ;    ebx=PID
  936. ;    ecx=address of message
  937. ;    edx=size of message
  938.  
  939.         dec     ebx
  940.         jnz     @f
  941.  
  942.         mov     eax,[current_slot]
  943.         pushf
  944.         cli
  945.         mov     [eax+APPDATA.ipc_start],ecx     ;set fields in extended information area
  946.         mov     [eax+APPDATA.ipc_size],edx
  947.  
  948.         add edx, ecx
  949.         add edx, 4095
  950.         and edx, not 4095
  951.  
  952. .touch: mov eax, [ecx]
  953.         add ecx, 0x1000
  954.         cmp ecx, edx
  955.         jb  .touch
  956.  
  957.         popf
  958.         mov [esp+32], ebx       ;ebx=0
  959.         ret
  960.  
  961. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  962. ;2
  963. @@:
  964.         dec     ebx
  965.         jnz     @f
  966.  
  967.         stdcall sys_ipc_send, ecx, edx, esi
  968.         mov     [esp+32], eax
  969.         ret
  970. @@:
  971.         or      eax,-1
  972.         mov     [esp+32], eax
  973.         ret
  974.  
  975. ;align 4
  976. ;proc set_ipc_buff
  977.  
  978. ;           mov  eax,[current_slot]
  979. ;           pushf
  980. ;           cli
  981. ;           mov  [eax+APPDATA.ipc_start],ebx     ;set fields in extended information area
  982. ;           mov  [eax+APPDATA.ipc_size],ecx
  983. ;
  984. ;           add ecx, ebx
  985. ;           add ecx, 4095
  986. ;           and ecx, not 4095
  987. ;
  988. ;.touch:    mov eax, [ebx]
  989. ;           add ebx, 0x1000
  990. ;           cmp ebx, ecx
  991. ;           jb  .touch
  992. ;
  993. ;           popf
  994. ;           xor eax, eax
  995. ;           ret
  996. ;endp
  997.  
  998. proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
  999.            locals
  1000.              dst_slot   dd ?
  1001.              dst_offset dd ?
  1002.              buf_size   dd ?
  1003.              used_buf   dd ?
  1004.            endl
  1005.  
  1006.            pushf
  1007.            cli
  1008.  
  1009.            mov  eax, [PID]
  1010.            call pid_to_slot
  1011.            test eax,eax
  1012.            jz   .no_pid
  1013.  
  1014.            mov [dst_slot], eax
  1015.            shl  eax,8
  1016.            mov  edi,[eax+SLOT_BASE+0xa0]  ;is ipc area defined?
  1017.            test edi,edi
  1018.            jz   .no_ipc_area
  1019.  
  1020.            mov ebx, edi
  1021.            and ebx, 0xFFF
  1022.            mov [dst_offset], ebx
  1023.  
  1024.            mov esi, [eax+SLOT_BASE+0xa4]
  1025.            mov [buf_size], esi
  1026.  
  1027.            mov ecx, [ipc_tmp]
  1028.            cmp esi, 0x40000-0x1000 ; size of [ipc_tmp] minus one page
  1029.            jbe @f
  1030.            push esi edi
  1031.            add esi,0x1000
  1032.            stdcall alloc_kernel_space,esi
  1033.            mov ecx, eax
  1034.            pop edi esi
  1035. @@:
  1036.            mov [used_buf], ecx
  1037.            stdcall map_mem, ecx, [dst_slot],\
  1038.                              edi, esi, PG_SW
  1039.  
  1040.            mov edi, [dst_offset]
  1041.            add edi, [used_buf]
  1042.            cmp dword [edi], 0
  1043.            jnz  .ipc_blocked          ;if dword [buffer]<>0 - ipc blocked now
  1044.  
  1045.            mov edx, dword [edi+4]
  1046.            lea ebx, [edx+8]
  1047.            add ebx, [msg_size]
  1048.            cmp ebx, [buf_size]
  1049.            ja .buffer_overflow         ;esi<0 - not enough memory in buffer
  1050.  
  1051.            mov dword [edi+4], ebx
  1052.            mov eax,[TASK_BASE]
  1053.            mov eax, [eax+0x04]         ;eax - our PID
  1054.            add edi, edx
  1055.            mov [edi], eax
  1056.            mov ecx, [msg_size]
  1057.  
  1058.            mov [edi+4], ecx
  1059.            add edi, 8
  1060.            mov esi, [msg_addr]
  1061.        ;    add esi, new_app_base
  1062.            cld
  1063.            rep movsb
  1064.  
  1065.            mov ebx, [ipc_tmp]
  1066.            mov edx, ebx
  1067.            shr ebx, 12
  1068.            xor eax, eax
  1069.            mov [page_tabs+ebx*4], eax
  1070.            invlpg [edx]
  1071.  
  1072.            mov ebx, [ipc_pdir]
  1073.            mov edx, ebx
  1074.            shr ebx, 12
  1075.            xor eax, eax
  1076.            mov [page_tabs+ebx*4], eax
  1077.            invlpg [edx]
  1078.  
  1079.            mov ebx, [ipc_ptab]
  1080.            mov edx, ebx
  1081.            shr ebx, 12
  1082.            xor eax, eax
  1083.            mov [page_tabs+ebx*4], eax
  1084.            invlpg [edx]
  1085.  
  1086.            mov  eax, [dst_slot]
  1087.            shl eax, 8
  1088.            or   [eax+SLOT_BASE+0xA8],dword 0x40
  1089.            cmp  dword [check_idle_semaphore],20
  1090.            jge  .ipc_no_cis
  1091.  
  1092.            mov  dword [check_idle_semaphore],5
  1093. .ipc_no_cis:
  1094.            push 0
  1095.            jmp .ret
  1096. .no_pid:
  1097.            popf
  1098.            mov eax, 4
  1099.            ret
  1100. .no_ipc_area:
  1101.            popf
  1102.            xor eax, eax
  1103.            inc eax
  1104.            ret
  1105. .ipc_blocked:
  1106.            push 2
  1107.            jmp .ret
  1108. .buffer_overflow:
  1109.            push 3
  1110. .ret:
  1111.            mov eax, [used_buf]
  1112.            cmp eax, [ipc_tmp]
  1113.            jz @f
  1114.            stdcall free_kernel_space,eax
  1115. @@:
  1116.            pop eax
  1117.            popf
  1118.            ret
  1119. endp
  1120.  
  1121. align 4
  1122. sysfn_meminfo:
  1123.  
  1124.         ;   add ecx, new_app_base
  1125.            cmp ecx, OS_BASE
  1126.            jae .fail
  1127.  
  1128.            mov eax, [pg_data.pages_count]
  1129.            mov [ecx], eax
  1130.            shl eax, 12
  1131.            mov [esp+32], eax
  1132.            mov eax, [pg_data.pages_free]
  1133.            mov [ecx+4], eax
  1134.            mov eax, [pg_data.pages_faults]
  1135.            mov [ecx+8], eax
  1136.            mov eax, [heap_size]
  1137.            mov [ecx+12], eax
  1138.            mov eax, [heap_free]
  1139.            mov [ecx+16], eax
  1140.            mov eax, [heap_blocks]
  1141.            mov [ecx+20], eax
  1142.            mov eax, [free_blocks]
  1143.            mov [ecx+24], eax
  1144.            ret
  1145. .fail:
  1146.            or dword [esp+32], -1
  1147.            ret
  1148. iglobal
  1149. align 4
  1150. f68call:
  1151.            dd f68.11   ; init_heap
  1152.            dd f68.12   ; user_alloc
  1153.            dd f68.13   ; user_free
  1154.            dd f68.14   ; get_event_ex
  1155.            dd f68.fail ;moved to f68.24
  1156.            dd f68.16   ; get_service
  1157.            dd f68.17   ; call_service
  1158.            dd f68.fail ;moved to f68.25
  1159.            dd f68.19   ; load_dll
  1160.            dd f68.20   ; user_realloc
  1161.            dd f68.21   ; load_driver
  1162.            dd f68.22   ; shmem_open
  1163.            dd f68.23   ; shmem_close
  1164.            dd f68.24
  1165.            dd f68.25
  1166. endg
  1167. align 4
  1168. f68:
  1169.            cmp  ebx,4
  1170.            jbe  sys_sheduler
  1171.  
  1172.            cmp ebx, 11
  1173.            jb .fail
  1174.  
  1175.            cmp ebx, 25
  1176.            ja .fail
  1177.  
  1178.            jmp dword [f68call+ebx*4-11*4]
  1179. .11:
  1180.            call init_heap
  1181.            mov [esp+32], eax
  1182.            ret
  1183. .12:
  1184.            stdcall user_alloc, ecx
  1185.            mov [esp+32], eax
  1186.            ret
  1187. .13:
  1188.            stdcall user_free, ecx
  1189.            mov [esp+32], eax
  1190.            ret
  1191. .14:
  1192.            cmp ecx, OS_BASE
  1193.            jae .fail
  1194.            mov edi,ecx
  1195.            call get_event_ex
  1196.            mov [esp+32], eax
  1197.            ret
  1198. .16:
  1199.            test ecx, ecx
  1200.            jz .fail
  1201.            cmp ecx, OS_BASE
  1202.            jae .fail
  1203.            stdcall get_service, ecx
  1204.            mov [esp+32], eax
  1205.            ret
  1206. .17:
  1207.            call srv_handlerEx   ;ecx
  1208.            mov [esp+32], eax
  1209.            ret
  1210. .19:
  1211.            cmp ecx, OS_BASE
  1212.            jae .fail
  1213.            stdcall load_library, ecx
  1214.            mov [esp+32], eax
  1215.            ret
  1216. .20:
  1217.            mov     eax, edx
  1218.            mov     ebx, ecx
  1219.            call    user_realloc         ;in: eax = pointer, ebx = new size
  1220.            mov     [esp+32], eax
  1221.            ret
  1222. .21:
  1223.            cmp ecx, OS_BASE
  1224.            jae .fail
  1225.  
  1226.            cmp ebx, OS_BASE
  1227.            jae .fail
  1228.  
  1229.            mov edi, edx
  1230.            stdcall load_PE, ecx
  1231.            mov esi, eax
  1232.            test eax, eax
  1233.            jz @F
  1234.  
  1235.            push edi
  1236.            push DRV_ENTRY
  1237.            call eax
  1238.            add esp, 8
  1239.            test eax, eax
  1240.            jz @F
  1241.  
  1242.            mov [eax+SRV.entry], esi
  1243.  
  1244. @@:
  1245.            mov [esp+32], eax
  1246.            ret
  1247. .22:
  1248.            cmp ecx, OS_BASE
  1249.            jae .fail
  1250.  
  1251.            stdcall shmem_open, ecx, edx, esi
  1252.            mov [esp+24], edx
  1253.            mov [esp+32], eax
  1254.            ret
  1255.  
  1256. .23:
  1257.            cmp ecx, OS_BASE
  1258.            jae .fail
  1259.  
  1260.            stdcall shmem_close, ecx
  1261.            mov [esp+32], eax
  1262.            ret
  1263. .24:
  1264.            mov  eax, [current_slot]
  1265.            xchg ecx, [eax+APPDATA.exc_handler]
  1266.            xchg edx, [eax+APPDATA.except_mask]
  1267.            mov  [esp+32], ecx ; reg_eax+8
  1268.            mov  [esp+20], edx ; reg_ebx+8
  1269.            ret
  1270. .25:
  1271.            cmp ecx,32
  1272.            jae .fail
  1273.            mov  eax, [current_slot]
  1274.            btr  [eax+APPDATA.except_mask],ecx
  1275.            setc byte[esp+32]
  1276.            jecxz @f
  1277.            bts  [eax+APPDATA.except_mask],ecx
  1278. @@:
  1279.            ret
  1280.  
  1281. .fail:
  1282.            xor eax, eax
  1283.            mov [esp+32], eax
  1284.            ret
  1285.  
  1286. align 4
  1287. proc load_pe_driver stdcall, file:dword
  1288.  
  1289.            stdcall load_PE, [file]
  1290.            test eax, eax
  1291.            jz .fail
  1292.  
  1293.            mov esi, eax
  1294.            stdcall eax, DRV_ENTRY
  1295.            test eax, eax
  1296.            jz .fail
  1297.  
  1298.            mov [eax+SRV.entry], esi
  1299.            ret
  1300.  
  1301. .fail:
  1302.            xor eax, eax
  1303.            ret
  1304. endp
  1305.  
  1306.  
  1307. align 4
  1308. proc init_mtrr
  1309.  
  1310.            cmp [BOOT_VAR+0x901c],byte 2
  1311.            je  .exit
  1312.  
  1313.            bt [cpu_caps], CAPS_MTRR
  1314.            jnc .exit
  1315.  
  1316.            mov eax, cr0
  1317.            or eax, 0x60000000   ;disable caching
  1318.            mov cr0, eax
  1319.            wbinvd               ;invalidate cache
  1320.  
  1321.            mov ecx, 0x2FF
  1322.            rdmsr                ;
  1323. ; has BIOS already initialized MTRRs?
  1324.            test ah, 8
  1325.            jnz .skip_init
  1326. ; rarely needed, so mainly placeholder
  1327. ; main memory - cached
  1328.            push eax
  1329.  
  1330.            mov eax, [MEM_AMOUNT]
  1331. ; round eax up to next power of 2
  1332.            dec eax
  1333.            bsr ecx, eax
  1334.            mov ebx, 2
  1335.            shl ebx, cl
  1336.            dec ebx
  1337. ; base of memory range = 0, type of memory range = MEM_WB
  1338.            xor edx, edx
  1339.            mov eax, MEM_WB
  1340.            mov ecx, 0x200
  1341.            wrmsr
  1342. ; mask of memory range = 0xFFFFFFFFF - (size - 1), ebx = size - 1
  1343.            mov eax, 0xFFFFFFFF
  1344.            mov edx, 0x0000000F
  1345.            sub eax, ebx
  1346.            sbb edx, 0
  1347.            or eax, 0x800
  1348.            inc ecx
  1349.            wrmsr
  1350. ; clear unused MTRRs
  1351.            xor eax, eax
  1352.            xor edx, edx
  1353. @@:
  1354.            wrmsr
  1355.            inc ecx
  1356.            cmp ecx, 0x210
  1357.            jb @b
  1358. ; enable MTRRs
  1359.            pop eax
  1360.            or ah, 8
  1361.            and al, 0xF0 ; default memtype = UC
  1362.            mov ecx, 0x2FF
  1363.            wrmsr
  1364. .skip_init:
  1365.            stdcall set_mtrr, [LFBAddress],[LFBSize],MEM_WC
  1366.  
  1367.            wbinvd               ;again invalidate
  1368.  
  1369.            mov eax, cr0
  1370.            and eax, not 0x60000000
  1371.            mov cr0, eax         ; enable caching
  1372. .exit:
  1373.            ret
  1374. endp
  1375.  
  1376. align 4
  1377. proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
  1378. ; find unused register
  1379.            mov ecx, 0x201
  1380. @@:
  1381.            rdmsr
  1382.            dec ecx
  1383.            test ah, 8
  1384.            jz .found
  1385.            rdmsr
  1386.            mov al, 0 ; clear memory type field
  1387.            cmp eax, [base]
  1388.            jz .ret
  1389.            add ecx, 3
  1390.            cmp ecx, 0x210
  1391.            jb @b
  1392. ; no free registers, ignore the call
  1393. .ret:
  1394.            ret
  1395. .found:
  1396. ; found, write values
  1397.            xor edx, edx
  1398.            mov eax, [base]
  1399.            or eax, [mem_type]
  1400.            wrmsr
  1401.  
  1402.            mov ebx, [size]
  1403.            dec ebx
  1404.            mov eax, 0xFFFFFFFF
  1405.            mov edx, 0x0000000F
  1406.            sub eax, ebx
  1407.            sbb edx, 0
  1408.            or eax, 0x800
  1409.            inc ecx
  1410.            wrmsr
  1411.            ret
  1412. endp
  1413.  
  1414. align 4
  1415. proc stall stdcall, delay:dword
  1416.            push ecx
  1417.            push edx
  1418.            push ebx
  1419.            push eax
  1420.  
  1421.            mov eax, [delay]
  1422.            mul [stall_mcs]
  1423.            mov ebx, eax       ;low
  1424.            mov ecx, edx       ;high
  1425.            rdtsc
  1426.            add ebx, eax
  1427.            adc ecx,edx
  1428. @@:
  1429.            rdtsc
  1430.            sub eax, ebx
  1431.            sbb edx, ecx
  1432.            jb @B
  1433.  
  1434.            pop eax
  1435.            pop ebx
  1436.            pop edx
  1437.            pop ecx
  1438.            ret
  1439. endp
  1440.  
  1441. align 4
  1442. proc create_ring_buffer stdcall, size:dword, flags:dword
  1443.            locals
  1444.              buf_ptr  dd ?
  1445.            endl
  1446.  
  1447.            mov eax, [size]
  1448.            test eax, eax
  1449.            jz .fail
  1450.  
  1451.            add eax, eax
  1452.            stdcall alloc_kernel_space, eax
  1453.            test eax, eax
  1454.            jz .fail
  1455.  
  1456.            push ebx
  1457.  
  1458.            mov [buf_ptr], eax
  1459.  
  1460.            mov ebx, [size]
  1461.            shr ebx, 12
  1462.            push ebx
  1463.  
  1464.            stdcall alloc_pages, ebx
  1465.            pop ecx
  1466.  
  1467.            test eax, eax
  1468.            jz .mm_fail
  1469.  
  1470.            push edi
  1471.  
  1472.            or eax, [flags]
  1473.            mov edi, [buf_ptr]
  1474.            mov ebx, [buf_ptr]
  1475.            mov edx, ecx
  1476.            shl edx, 2
  1477.            shr edi, 10
  1478. @@:
  1479.            mov [page_tabs+edi], eax
  1480.            mov [page_tabs+edi+edx], eax
  1481.            invlpg [ebx]
  1482.            invlpg [ebx+0x10000]
  1483.            add eax, 0x1000
  1484.            add ebx, 0x1000
  1485.            add edi, 4
  1486.            dec ecx
  1487.            jnz @B
  1488.  
  1489.            mov eax, [buf_ptr]
  1490.            pop edi
  1491.            pop ebx
  1492.            ret
  1493. .mm_fail:
  1494.            stdcall free_kernel_space, [buf_ptr]
  1495.            xor eax, eax
  1496.            pop ebx
  1497. .fail:
  1498.            ret
  1499. endp
  1500.