1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Copyright (C) KolibriOS team 2004-2022. All rights reserved. ;;
4 ;; Distributed under terms of the GNU General Public License ;;
6 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 MEM_BLOCK_RESERVED = 0x02 ; Will be allocated on first access (lazy allocation)
24 MEM_BLOCK_DONT_FREE = 0x10
38 mov eax, [esi + MEM_BLOCK.base]
39 mov ebx, [esi + MEM_BLOCK.base]
46 inc [mem_hash_cnt + eax*4]
48 lea ecx, [mem_used_list + eax*8]
50 mov [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
51 mov eax, [esi + MEM_BLOCK.size]
65 lea ebx, [mem_used_list + ecx*8]
68 mov esi, [esi + MEM_BLOCK.list.next]
72 cmp eax, [esi + MEM_BLOCK.base]
86 cmp [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
89 dec [mem_hash_cnt + ecx*4]
93 .fatal: ;FIXME panic here
99 ; + heap_size terminator MEM_BLOCK_USED
100 ; + 4096*MEM_BLOCK.sizeof free space MEM_BLOCK_FREE
101 ;HEAP_BASE heap_descriptors MEM_BLOCK_USED
105 proc init_kernel_heap
108 mov edi, mem_block_list
116 mov edi, mem_used_list
123 stdcall alloc_pages, dword 32
130 mov edi, HEAP_BASE ;descriptors
131 mov ebx, HEAP_BASE + sizeof.MEM_BLOCK ;free space
132 mov ecx, HEAP_BASE + sizeof.MEM_BLOCK*2 ;terminator
135 mov [edi + MEM_BLOCK.next_block], ebx
136 mov [edi + MEM_BLOCK.prev_block], eax
137 mov [edi + MEM_BLOCK.list.next], eax
138 mov [edi + MEM_BLOCK.list.prev], eax
139 mov [edi + MEM_BLOCK.base], HEAP_BASE
140 mov [edi + MEM_BLOCK.size], 4096*sizeof.MEM_BLOCK
141 mov [edi + MEM_BLOCK.flags], MEM_BLOCK_USED
143 mov [ecx + MEM_BLOCK.next_block], eax
144 mov [ecx + MEM_BLOCK.prev_block], ebx
145 mov [ecx + MEM_BLOCK.list.next], eax
146 mov [ecx + MEM_BLOCK.list.prev], eax
147 mov [ecx + MEM_BLOCK.base], eax
148 mov [ecx + MEM_BLOCK.size], eax
149 mov [ecx + MEM_BLOCK.flags], MEM_BLOCK_USED
151 mov [ebx + MEM_BLOCK.next_block], ecx
152 mov [ebx + MEM_BLOCK.prev_block], edi
153 mov [ebx + MEM_BLOCK.base], HEAP_BASE + 4096*sizeof.MEM_BLOCK
155 mov ecx, [pg_data.kernel_pages]
157 sub ecx, HEAP_BASE-OS_BASE + 4096*sizeof.MEM_BLOCK
160 mov [ebx + MEM_BLOCK.size], ecx
161 mov [ebx + MEM_BLOCK.flags], MEM_BLOCK_FREE
163 mov [mem_block_mask], eax
164 mov [mem_block_mask + 4], 0x80000000
166 mov ecx, mem_block_list + 63*8
170 mov eax, HEAP_BASE + sizeof.MEM_BLOCK*4
172 mov [next_memblock], HEAP_BASE + sizeof.MEM_BLOCK *3
174 mov [eax - sizeof.MEM_BLOCK], eax
175 add eax, sizeof.MEM_BLOCK
178 mov dword[eax - sizeof.MEM_BLOCK], 0
182 mov [heap_blocks], 4094
183 mov [free_blocks], 4093
191 ; edi= memory block descriptor
192 ; ebx= descriptor index
203 lea esi, [mem_block_mask]
220 lea ecx, [mem_block_list + ebx*8]
223 mov edi, [edi + MEM_BLOCK.list.next]
226 cmp eax, [edi + MEM_BLOCK.size]
235 cmp esi, mem_block_mask + 8
245 mov ebx, [next_memblock]
247 mov [next_memblock], eax
250 mov dword[eax + 4], ebx
251 mov dword[eax + 8], ebx
252 mov dword[eax + 12], ebx
253 mov dword[eax + 16], ebx
254 ; mov dword[eax + 20], 0 ;don't clear block size
255 mov dword[eax + 24], ebx
256 mov dword[eax + 28], ebx
263 proc alloc_kernel_space stdcall, size:dword
264 local block_ind:DWORD
278 spin_lock_irqsave heap_mutex
282 call get_small_block ; eax
286 cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
289 mov [block_ind], ebx ;index of allocated block
291 mov eax, [edi + MEM_BLOCK.size]
295 mov esi, [next_memblock] ;new memory block
301 mov [next_memblock], eax
303 mov [esi + MEM_BLOCK.next_block], edi
304 mov eax, [edi + MEM_BLOCK.prev_block]
305 mov [esi + MEM_BLOCK.prev_block], eax
306 mov [edi + MEM_BLOCK.prev_block], esi
307 mov [esi + MEM_BLOCK.list.next], 0
308 mov [esi + MEM_BLOCK.list.prev], 0
309 mov [eax + MEM_BLOCK.next_block], esi
311 mov ebx, [edi + MEM_BLOCK.base]
312 mov [esi + MEM_BLOCK.base], ebx
314 mov [esi + MEM_BLOCK.size], edx
315 add [edi + MEM_BLOCK.base], edx
316 sub [edi + MEM_BLOCK.size], edx
318 mov eax, [edi + MEM_BLOCK.size]
326 lea edx, [mem_block_list + ecx*8]
329 btr [mem_block_mask], ecx
331 bts [mem_block_mask], eax
332 lea edx, [mem_block_list + eax*8] ;edx= list head
338 spin_unlock_irqrestore heap_mutex
339 mov eax, [esi + MEM_BLOCK.base]
347 lea edx, [mem_block_list + ebx*8]
350 btr [mem_block_mask], ebx
356 spin_unlock_irqrestore heap_mutex
366 proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
368 spin_lock_irqsave heap_mutex
372 call md.del_from_used
376 mov eax, [esi + MEM_BLOCK.size]
379 mov edi, [esi + MEM_BLOCK.next_block]
380 cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
385 mov edx, [edi + MEM_BLOCK.next_block]
386 mov [esi + MEM_BLOCK.next_block], edx
387 mov [edx + MEM_BLOCK.prev_block], esi
388 mov ecx, [edi + MEM_BLOCK.size]
389 add [esi + MEM_BLOCK.size], ecx
393 lea edx, [mem_block_list + ecx*8]
396 btr [mem_block_mask], ecx
401 mov edi, [esi + MEM_BLOCK.prev_block]
402 cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
405 mov edx, [esi + MEM_BLOCK.next_block]
406 mov [edi + MEM_BLOCK.next_block], edx
407 mov [edx + MEM_BLOCK.prev_block], edi
412 mov ecx, [edi + MEM_BLOCK.size]
413 mov eax, [esi + MEM_BLOCK.size]
415 mov [edi + MEM_BLOCK.size], eax
417 calc_index eax ;new index
418 calc_index ecx ;old index
426 lea edx, [mem_block_list + ecx*8]
429 btr [mem_block_mask], ecx
432 bts [mem_block_mask], eax
433 lea edx, [mem_block_list + eax*8]
436 spin_unlock_irqrestore heap_mutex
441 mov [esi + MEM_BLOCK.flags], MEM_BLOCK_FREE
442 mov eax, [esi + MEM_BLOCK.size]
448 spin_unlock_irqrestore heap_mutex
454 proc kernel_alloc stdcall, size:dword
471 mov [pages_count], ebx
473 stdcall alloc_kernel_space, eax
475 mov ebx, [pages_count]
485 stdcall alloc_pages, ebx
490 or eax, PG_GLOBAL + PG_SWR
494 mov edx, ebx ; this dirty hack
496 mov ebx, [pages_count]
504 stdcall map_page, edx, eax, dword (PG_GLOBAL + PG_SWR)
521 proc kernel_free stdcall, base:dword
525 spin_lock_irqsave heap_mutex
530 cmp [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
533 spin_unlock_irqrestore heap_mutex
535 mov eax, [esi + MEM_BLOCK.base]
536 mov ecx, [esi + MEM_BLOCK.size]
538 call release_pages ;eax, ecx
539 stdcall free_kernel_space, [base]
543 spin_unlock_irqrestore heap_mutex
549 ;;;;;;;;;;;;;; USER HEAP ;;;;;;;;;;;;;;;;;
551 HEAP_TOP = 0x80000000
556 mov ebx, [current_process]
557 mov eax, [ebx + PROC.heap_top]
560 sub eax, [ebx + PROC.heap_base]
564 lea ecx, [ebx + PROC.heap_lock]
567 mov esi, [ebx + PROC.mem_used]
570 mov [ebx + PROC.mem_used], esi
572 mov [ebx + PROC.heap_base], esi
573 mov [ebx + PROC.heap_top], eax
579 or ecx, MEM_BLOCK_FREE
580 mov [page_tabs + esi], ecx
585 proc user_alloc stdcall, alloc_size:dword
589 mov ebx, [current_process]
590 lea ecx, [ebx + PROC.heap_lock]
593 mov ecx, [alloc_size]
594 add ecx, (4095 + PAGE_SIZE)
596 mov esi, [ebx + PROC.heap_base]
597 mov edi, [ebx + PROC.heap_top]
604 mov eax, [page_tabs + ebx*4]
605 test al, MEM_BLOCK_FREE
608 cmp eax, ecx ;alloc_size
614 or al, MEM_BLOCK_FREE
616 mov [page_tabs + edx*4], eax
618 or ecx, MEM_BLOCK_USED
619 mov [page_tabs + ebx*4], ecx
625 mov dword [page_tabs + ebx*4], MEM_BLOCK_RESERVED
631 mov edx, [current_process]
632 mov ebx, [alloc_size]
635 add [edx + PROC.mem_used], ebx
637 lea ecx, [edx + PROC.heap_lock]
640 lea eax, [esi + 4096]
647 test al, MEM_BLOCK_USED
650 and eax, 0xFFFFF000 ; not PAGESIZE
655 mov ecx, [current_process]
656 lea ecx, [ecx + PROC.heap_lock]
667 proc user_alloc_at stdcall, address:dword, alloc_size:dword
673 mov ebx, [current_process]
674 lea ecx, [ebx + PROC.heap_lock]
682 mov esi, [ebx + PROC.heap_base]
683 mov edi, [ebx + PROC.heap_top]
691 mov eax, [page_tabs + ebx*4]
700 mov ecx, [current_process]
701 lea ecx, [ecx + PROC.heap_lock]
710 test al, MEM_BLOCK_FREE
715 cmp eax, [alloc_size]
718 ; Here we have 1 big free block which includes requested area.
719 ; In general, 3 other blocks must be created instead:
720 ; free at [esi, edx);
721 ; busy at [edx, edx + 0x1000 + ALIGN_UP(alloc_size,0x1000));
722 ; free at [edx + 0x1000 + ALIGN_UP(alloc_size,0x1000), ecx)
723 ; First or third block (or both) may be absent.
727 or al, MEM_BLOCK_FREE
728 mov [page_tabs + ebx*4], eax
730 mov eax, [alloc_size]
736 or al, MEM_BLOCK_USED
737 mov [page_tabs + ebx*4], eax
743 mov dword [page_tabs + ebx*4], MEM_BLOCK_RESERVED
751 or cl, MEM_BLOCK_FREE
752 mov [page_tabs + ebx*4], ecx
755 mov edx, [current_process]
756 mov ebx, [alloc_size]
759 add [edx + PROC.mem_used], ebx
761 lea ecx, [edx + PROC.heap_lock]
773 proc user_free stdcall, base:dword
783 mov ebx, [current_process]
784 lea ecx, [ebx + PROC.heap_lock]
789 mov eax, [page_tabs + (esi-1)*4]
790 test al, MEM_BLOCK_USED
792 test al, MEM_BLOCK_DONT_FREE
797 or al, MEM_BLOCK_FREE
798 mov [page_tabs + (esi-1)*4], eax
805 xchg eax, [page_tabs + esi*4]
822 mov edx, [current_process]
823 lea ecx, [edx + PROC.heap_lock]
824 mov esi, dword [edx + PROC.heap_base]
825 mov edi, dword [edx + PROC.heap_top]
826 sub ebx, [edx + PROC.mem_used]
828 mov [edx + PROC.mem_used], ebx
841 mov ecx, [current_process]
842 lea ecx, [ecx + PROC.heap_lock]
852 proc user_unmap stdcall, base:dword, offset:dword, size:dword
856 mov ebx, [base] ; must be valid pointer
860 mov edx, [offset] ; check offset
861 add edx, ebx ; must be below 2Gb app limit
864 shr ebx, 12 ; chek block attributes
865 lea ebx, [page_tabs + ebx*4]
866 mov eax, [ebx - 4] ; block attributes
867 test al, MEM_BLOCK_USED
869 test al, MEM_BLOCK_DONT_FREE
873 lea edx, [page_tabs + edx*4] ; unmap offset
877 shr ecx, 12 ; unmap size in pages
879 shr eax, 12 ; block size + 1 page
880 lea ebx, [ebx + eax*4-4] ; block end ptr
881 lea eax, [edx + ecx*4] ; unmap end ptr
883 cmp eax, ebx ; check for overflow
887 and ebx, not 4095 ; is it required ?
891 mov eax, [edx] ; get page addres
892 test al, 1 ; page mapped ?
894 test eax, PG_SHARED ; page shared ?
896 mov dword[edx], MEM_BLOCK_RESERVED
897 ; mark page as reserved
898 invlpg [ebx] ; when we start using
899 call free_page ; empty c-o-w page instead this ?
901 add ebx, 4096 ; PAGESIZE?
907 or al, 1 ; return non zero on success
911 xor eax, eax ; something wrong
917 ; in: esi=heap_base, edi=heap_top
919 ; destroys: ebx,edx,esi,edi
923 mov eax, [page_tabs + esi*4]
924 test al, MEM_BLOCK_USED
930 test al, MEM_BLOCK_FREE
938 mov ebx, [page_tabs + edx*4]
939 test bl, MEM_BLOCK_USED
947 test bl, MEM_BLOCK_FREE
949 and dword[page_tabs + edx*4], 0
951 and eax, not 4095 ; not (PAGESIZE - 1) ?
952 or eax, MEM_BLOCK_FREE
953 mov [page_tabs + esi*4], eax
964 ; in: eax = pointer, ebx = new size
965 ; out: eax = new pointer or NULL
968 ; realloc(NULL,sz) - same as malloc(sz)
976 mov ecx, [current_process]
977 lea ecx, [ecx + PROC.heap_lock]
981 lea ecx, [eax - 0x1000]
983 mov edx, [page_tabs + ecx*4]
984 test dl, MEM_BLOCK_USED
986 ; attempt to realloc invalid pointer
988 mov ecx, [current_process]
989 lea ecx, [ecx + PROC.heap_lock]
996 test dl, MEM_BLOCK_DONT_FREE
1001 ; edx = allocated size, ebx = new size
1006 ; release part of allocated memory
1012 xchg eax, [page_tabs + edx*4]
1024 mov eax, [page_tabs + ecx*4]
1026 mov edx, [current_process]
1027 mov ebx, [edx + PROC.mem_used]
1030 or al, MEM_BLOCK_FREE
1031 mov [page_tabs + ecx*4], eax
1033 mov esi, [edx + PROC.heap_base]
1034 mov edi, [edx + PROC.heap_top]
1035 mov [edx + PROC.mem_used], ebx
1038 jmp .ret0 ; all freed
1042 or ebx, MEM_BLOCK_USED
1043 xchg [page_tabs + ecx*4], ebx
1047 mov edx, [current_process]
1049 sub ebx, [edx + PROC.mem_used]
1051 mov [edx + PROC.mem_used], ebx
1057 lea edx, [ecx + ebx]
1061 mov esi, [current_process]
1062 mov esi, [esi + PROC.heap_top]
1067 mov eax, [page_tabs + edx*4]
1068 test al, MEM_BLOCK_USED
1070 and dword [page_tabs + edx*4], 0
1078 or ebx, MEM_BLOCK_FREE
1079 mov [page_tabs + ecx*4], ebx
1081 mov ecx, [current_process]
1082 lea ecx, [ecx + PROC.heap_lock]
1088 ; get some additional memory
1089 mov eax, [current_process]
1090 mov eax, [eax + PROC.heap_top]
1094 mov eax, [page_tabs + edx*4]
1095 test al, MEM_BLOCK_FREE
1103 or al, MEM_BLOCK_FREE
1104 mov [page_tabs + ebx*4], eax
1109 or al, MEM_BLOCK_USED
1110 mov [page_tabs + ecx*4], eax
1115 lea edi, [page_tabs + edx*4]
1122 mov edx, [current_process]
1124 add [edx + PROC.mem_used], ebx
1126 mov ecx, [current_process]
1127 lea ecx, [ecx + PROC.heap_lock]
1134 mov eax, [current_process]
1135 mov esi, [eax + PROC.heap_base]
1136 mov edi, [eax + PROC.heap_top]
1142 jae .place_not_found
1143 mov eax, [page_tabs + esi*4]
1144 test al, MEM_BLOCK_FREE
1164 or al, MEM_BLOCK_FREE
1165 mov [page_tabs + esi*4], eax
1170 or al, MEM_BLOCK_USED
1171 mov [page_tabs + esi*4], eax
1176 mov eax, [page_tabs + ecx*4]
1178 or al, MEM_BLOCK_FREE
1180 mov [page_tabs + ecx*4], eax
1187 xchg eax, [page_tabs + ecx*4]
1188 mov [page_tabs + esi*4], eax
1199 mov edx, [current_process]
1201 add [edx + PROC.mem_used], ebx
1204 mov dword [page_tabs + esi*4], MEM_BLOCK_RESERVED
1209 mov ecx, [current_process]
1210 lea ecx, [ecx + PROC.heap_lock]
1212 pop eax edi esi edx ecx
1217 ;;;;;;;;;;;;;; SHARED MEMORY ;;;;;;;;;;;;;;;;;
1221 ; eax= shm_map object
1233 mov esi, [eax + SMAP.parent]
1237 lock dec [esi + SMEM.refcount]
1240 mov ecx, [esi + SMEM.bk]
1241 mov edx, [esi + SMEM.fd]
1243 mov [ecx + SMEM.fd], edx
1244 mov [edx + SMEM.bk], ecx
1246 stdcall kernel_free, [esi + SMEM.base]
1251 call destroy_kernel_object
1270 SHM_OPEN_ALWAYS = 1 shl 2
1271 SHM_CREATE = 2 shl 2
1273 SHM_OPEN_MASK = 3 shl 2
1276 proc shmem_open stdcall name:dword, size:dword, access:dword
1288 mov [owner_access], 0
1290 pushfd ;mutex required
1294 and eax, SHM_OPEN_MASK
1302 mov esi, [shmem_list.fd]
1308 lea edx, [esi + SMEM.name]; link , base, size
1309 stdcall strncmp, edx, ebx, 32
1313 mov esi, [esi + SMEM.fd]
1327 cmp eax, SHM_OPEN_ALWAYS
1340 mov eax, sizeof.SMEM
1347 stdcall kernel_alloc, [size]
1355 and edx, SHM_ACCESS_MASK
1357 mov [esi + SMEM.base], eax
1358 mov [esi + SMEM.size], ecx
1359 mov [esi + SMEM.access], edx
1360 mov [esi + SMEM.refcount], 0
1361 mov [esi + SMEM.name + 28], 0
1363 lea eax, [esi + SMEM.name]
1364 stdcall strncpy, eax, [name], 31
1366 mov eax, [shmem_list.fd]
1367 mov [esi + SMEM.bk], shmem_list
1368 mov [esi + SMEM.fd], eax
1370 mov [eax + SMEM.bk], esi
1371 mov [shmem_list.fd], esi
1373 mov [action], SHM_OPEN
1374 mov [owner_access], SHM_WRITE
1387 cmp eax, SHM_OPEN_ALWAYS
1393 and eax, SHM_ACCESS_MASK
1394 cmp eax, [esi + SMEM.access]
1399 mov ebx, [current_slot]
1400 mov ebx, [ebx + APPDATA.tid]
1401 mov eax, sizeof.SMAP
1403 call create_kernel_object
1409 inc [esi + SMEM.refcount]
1411 mov [edi + SMAP.magic], 'SMAP'
1412 mov [edi + SMAP.destroy], destroy_smap
1413 mov [edi + SMAP.parent], esi
1414 mov [edi + SMAP.base], 0
1416 stdcall user_alloc, [esi + SMEM.size]
1422 mov [edi + SMAP.base], eax
1424 mov ecx, [esi + SMEM.size]
1430 mov esi, [esi + SMEM.base]
1432 lea edi, [page_tabs + eax]
1436 or edx, [owner_access]
1438 or edx, PG_SHARED + PG_UR
1448 cmp [owner_access], 0
1474 proc shmem_close stdcall, name:dword
1486 mov esi, [current_slot]
1487 add esi, APP_OBJ_OFFSET
1488 mov ebx, esi ; Fixed endless loop bug with not existing name (part 1)
1490 mov eax, [esi + APPOBJ.fd]
1494 cmp eax, ebx ;esi ; Fixed endless loop bug with not existing name (part 2)
1495 je @F ; Small optimization
1499 cmp [eax + SMAP.magic], 'SMAP'
1502 mov edi, [eax + SMAP.parent]
1506 lea edi, [edi + SMEM.name]
1507 stdcall strncmp, [name], edi, 32
1511 stdcall user_free, [esi + SMAP.base]
1514 call [esi + APPOBJ.destroy]
1526 proc user_ring stdcall, size:dword
1534 ; Size must be an exact multiple of pagesize
1536 test eax, PAGE_SIZE-1
1539 ; We must have at least one complete page
1542 mov [num_pages], eax
1544 ; Allocate double the virtual memory
1548 stdcall user_alloc, eax
1553 ; Now allocate physical memory
1554 stdcall alloc_pages, [num_pages]
1559 ; Map first half of virtual memory to physical memory
1561 mov ecx, [num_pages]
1565 stdcall map_page, esi, edi, PG_UWR
1571 ; Map second half of virtual memory to same physical memory
1572 mov ecx, [num_pages]
1575 stdcall map_page, esi, edi, PG_UWR
1586 stdcall user_free, [virt_ptr]