Compare commits

..

No commits in common. "f676062269443c9bd6d90ef386bb8056a32b023d" and "e6b057fe78b57e2da6105c918bcfa5682186441e" have entirely different histories.

5 changed files with 55 additions and 537 deletions

View file

@ -116,5 +116,4 @@ Format: 1.52
Alter Language: Assembly Alter Language: Assembly
Add Extensions: asm s inc Add Extensions: asm s inc
Function Prototype Ender: :
Struct Prototype Ender: } Struct Prototype Ender: }

View file

@ -87,12 +87,6 @@ Alter Topic Type: Macro
equ equ
Alter Topic Type: Section
Add Keywords:
mark
Topic Type: Struct Topic Type: Struct
Plural: Structs Plural: Structs

View file

@ -12,10 +12,10 @@ mm_init:
mov eax, stVmemKernel mov eax, stVmemKernel
push dword 4 push dword 4
push dword 5
push dword 0 push dword 0
push dword 0 push dword 0
push dword 0 push dword 0
push dword 4096
mov edx, PMM_VIRT_TEMP mov edx, PMM_VIRT_TEMP
mov ecx, kend mov ecx, kend
@ -25,13 +25,6 @@ mm_init:
call vmem_create call vmem_create
add esp, 24 add esp, 24
mov eax, stVmemKernel
mov edx, 4096
mov ecx, VMEM_VM_BESTFIT
call vmem_alloc
xchg bx, bx
ret ret
szVmemKernelName db "kmem", 0 szVmemKernelName db "kmem", 0

View file

@ -3,73 +3,41 @@
;; General purpose resource allocator. ;; General purpose resource allocator.
;; Based on <tinyvmem at https://github.com/rdmsr/tinyvmem> and on <Bonwick's paper at https://www.usenix.org/legacy/event/usenix01/full_papers/bonwick/bonwick.pdf> ;; Based on <tinyvmem at https://github.com/rdmsr/tinyvmem> and on <Bonwick's paper at https://www.usenix.org/legacy/event/usenix01/full_papers/bonwick/bonwick.pdf>
;;; MARK: Macros and structs ;;; MARK: macros and structs
;; Constant: VMEM_VM_BESTFIT VM_BESTFIT = (1 shl 0)
VMEM_VM_BESTFIT = (1 shl 0) VM_INSTANTFIT = (1 shl 1)
;; Constant: VMEM_VM_INSTANTFIT VM_NEXTFIT = (1 shl 2)
VMEM_VM_INSTANTFIT = (1 shl 1) VM_SLEEP = (1 shl 3)
;; Constant: VMEM_VM_SLEEP VM_NOSLEEP = (1 shl 4)
VMEM_VM_SLEEP = (1 shl 3) VM_BOOTSTRAP = (1 shl 5)
;; Constant: VMEM_VM_NOSLEEP
VMEM_VM_NOSLEEP = (1 shl 4)
;; Constant: VMEM_VM_BOOTSTRAP
VMEM_VM_BOOTSTRAP = (1 shl 5)
;; Constant: VMEM_VM_POPULATING
VMEM_VM_POPULATING = (1 shl 6)
;; Constant: VMEM_VM_FIT_MASK STATIC_SEG_COUNT = 64
VMEM_VM_FIT_MASK = (VMEM_VM_BESTFIT or VMEM_VM_INSTANTFIT)
;; Constant: VMEM_STATIC_SEG_COUNT FREELISTS_N = 4 * 8
VMEM_STATIC_SEG_COUNT = 64 HASHTABLE_N = 16
;; Constant: VMEM_MIN_RESERVE SEGMENT_ALLOCATED = 0
VMEM_MIN_RESERVE = 4 SEGMENT_FREE = 1
SEGMENT_SPAN = 2
;; Constant: VMEM_FREELISTS_N macro GET_LIST reg, N {
VMEM_FREELISTS_N = 4 * 8
;; Constant: VMEM_HASHTABLE_N
VMEM_HASHTABLE_N = 16
;; Constant: VMEM_SEGMENT_ALLOCATED
VMEM_SEGMENT_ALLOCATED = 0
;; Constant: VMEM_SEGMENT_FREE
VMEM_SEGMENT_FREE = 1
;; Constant: VMEM_SEGMENT_SPAN
VMEM_SEGMENT_SPAN = 2
;; Constant: VMEM_SEGMENT_STATIC_SPAN
VMEM_SEGMENT_STATIC_SPAN = 3
;; Constant: VMEM_ALLOC
VMEM_ALLOC = (1 shl 0)
;; Constant: VMEM_FREE
VMEM_FREE = (1 shl 1)
;; Constant: VMEM_MIN_ADDR
VMEM_ADDR_MIN = 0
;; Constant: VMEM_MAX_ADDR
VMEM_ADDR_MAX = -1
;; macro: VMEM_GET_LIST_FROM_SIZE
macro VMEM_GET_LIST_FROM_SIZE reg, N {
bsr reg, reg bsr reg, reg
xor reg, 31 xor reg, 31
add reg, -N add reg, -N
neg reg
sub reg, 1 sub reg, 1
} }
;; Struc: VmemSegment struc VmSegment {
struc VmemSegment { .type db ?
.type dd ? ; TODO: rework VmemSegment struct .imported db ?
.base dd ? .base dd ?
.size dd ? .size dd ?
.segqueue TailQEntry .spanlist ListEntry
.seglist ListEntry .seglist ListEntry
} }
DEFN VmemSegment DEFN VmSegment
;; Struc: Vmem ;; Struc: Vmem
struc Vmem { struc Vmem {
@ -82,15 +50,13 @@ struc Vmem {
.source dd ? .source dd ?
.flags dd ? .flags dd ?
.in_use dd ? .freelist dd FREELISTS_N dup(0)
.hashtable dd HASHTABLE_N dup(0)
.segqueue TailQHead .spanlist ListHead 0
.freelist dd VMEM_FREELISTS_N dup(0)
.hashtable dd VMEM_HASHTABLE_N dup(0)
} }
DEFN Vmem DEFN Vmem
;;; MARK: Private functions ;;; MARK: private functions
;; Function: _murmur32 ;; Function: _murmur32
;; ;;
@ -134,7 +100,7 @@ __hash_table_addr:
mov esi, eax mov esi, eax
mov eax, edx mov eax, edx
call _murmur32 call _murmur32
and eax, VMEM_HASHTABLE_N-1 ; x % y (y is a power of two) and eax, HASHTABLE_N-1 ; x % y (y is a power of two)
shl eax, 2 shl eax, 2
mov edx, esi mov edx, esi
@ -153,7 +119,7 @@ __hash_table_addr:
;; ;;
_vmem_segfree: _vmem_segfree:
; XXX: lock ; XXX: lock
add eax, VmemSegment.seglist add eax, VmSegment.seglist
mov edx, pVmemFreeSegHead mov edx, pVmemFreeSegHead
xchg eax, edx xchg eax, edx
call list_insert_head call list_insert_head
@ -166,12 +132,11 @@ _vmem_segfree:
;; Function: _vmem_segalloc ;; Function: _vmem_segalloc
;; ;;
;; Out: ;; Out:
;; EAX - Pointer to <VmemSegment> object on success, 0 on error ;; EAX - Pointer to <VmSegment> object on success, 0 on error
_vmem_segalloc: _vmem_segalloc:
push ebp push ebp
mov ebp, esp mov ebp, esp
; XXX: lock ; XXX: lock
mov eax, [pVmemFreeSegHead] mov eax, [pVmemFreeSegHead]
or eax, eax or eax, eax
jz .end jz .end
@ -181,11 +146,9 @@ _vmem_segalloc:
call list_remove call list_remove
sub ebx, VmemSegment.seglist sub ebx, VmSegment.seglist
dec [iVmemFreeSegCount] dec [iVmemFreeSegCount]
mov eax, ebx
pop ebx pop ebx
.end: .end:
@ -193,146 +156,8 @@ _vmem_segalloc:
leave leave
ret ret
;; Function: _vmem_refill
;;
_vmem_refill:
push ebp
mov ebp, esp
xor eax, eax ;;; MARK: public functions
; TODO: allocate page
;call kalloc()
or eax, eax
jz .end
push esi
push edi
mov esi, eax
xor edi, edi
@@:
mov eax, [esi]
call _vmem_segfree
inc [iVmemFreeSegCount]
add esi, sizeof.VmemSegment
add edi, sizeof.VmemSegment
cmp edi, PAGE_SIZE
jl @b
pop edi
pop esi
.end:
leave
ret
;; Function: _vmem_segfit
;;
;; Check if a <VmemSegment> meet restrictions.
;;
;; In:
;; EAX - seg
;; EDX - size
;; ECX - align
;; ESP[4] - phase
;; ESP[8] - nocross
;; ESP[12] - minaddr
;; ESP[16] - macaddr
;; ESP[20] - addrp
;;
_vmem_segfit:
xor eax, eax
ret
;; Function: _vmem_add
;;
;; In:
;; EAX - Pointer to <Vmem> object.
;; EDX - Address.
;; ECX - Size in bytes.
;; ESP[4] - Flags. (<VMEM_VM_SLEEP> or <VMEM_VM_NOSLEEP>)
;; ESP[8] - Span type (<VMEM_SEGMENT_SPAN> or <VMEM_SEGMENT_STATIC_SPAN>)
;;
;; Out:
;; EAX - 0 on success.
_vmem_add:
push ebp
mov ebp, esp
sub esp, 8
push esi
push edi
push ebx
mov esi, eax
mov edi, edx
mov ebx, ecx
; create new span
call _vmem_segalloc
or eax, eax
jz .end ; TODO: error handling
mov [eax + VmemSegment.base], edi
mov [eax + VmemSegment.size], ebx
mov edx, [ebp + 12] ; get span type
mov [eax + VmemSegment.type], edx
mov [ebp - 8], eax
; create free segment
call _vmem_segalloc
or eax, eax
jz .end ; TODO: error handling
mov [eax + VmemSegment.base], edi
mov [eax + VmemSegment.size], ebx
mov [eax + VmemSegment.type], VMEM_SEGMENT_FREE
mov [ebp - 4], eax
mov edx, [ebp - 8]
add edx, VmemSegment.segqueue
mov eax, esi
add eax, Vmem.segqueue
push eax
push edx
call tailq_insert_tail
pop edx
pop eax
mov ecx, [ebp - 4]
add ecx, VmemSegment.segqueue
call tailq_insert_after
VMEM_GET_LIST_FROM_SIZE ebx, VMEM_FREELISTS_N
shl ebx, 2
mov eax, esi
add eax, Vmem.freelist
add eax, ebx
mov edx, [ebp - 4]
add edx, VmemSegment.seglist
call list_insert_head
.end:
pop ebx
pop edi
pop esi
leave
ret
;; Function: _vmem_import
;;
_vmem_import:
ret
;;; MARK: Public functions
;; Function: vmem_create ;; Function: vmem_create
;; ;;
@ -347,7 +172,7 @@ _vmem_import:
;; ESP[12] - Alloc function. ;; ESP[12] - Alloc function.
;; ESP[16] - Free function. ;; ESP[16] - Free function.
;; ESP[20] - Source. ;; ESP[20] - Source.
;; ESP[24] - Flags. (<VMEM_VM_SLEEP> or <VMEM_VM_NOSLEEP>) ;; ESP[24] - Flags. (<VM_SLEEP> or <VM_NOSLEEP>)
vmem_create: vmem_create:
push ebp push ebp
mov ebp, esp mov ebp, esp
@ -395,10 +220,17 @@ vmem_create:
add edi, Vmem.size add edi, Vmem.size
rep movsd rep movsd
; initialize segqueue
mov eax, [ebp - 8] mov eax, [ebp - 8]
add eax, Vmem.segqueue mov edx, [ebp - 4]
mov [eax + 4], eax or edx, edx
jnz @f
mov ecx, [eax + Vmem.size]
or ecx, ecx
jz @f
push dword [eax + Vmem.flags]
call vmem_add
add esp, 4
@@:
if CONFIG_TRACE_VMEM if CONFIG_TRACE_VMEM
mov esi, [ebp - 8] mov esi, [ebp - 8]
@ -408,19 +240,6 @@ if CONFIG_TRACE_VMEM
TRACE szTraceVmemCreate, esi, edx, ecx TRACE szTraceVmemCreate, esi, edx, ecx
end if end if
mov eax, [ebp - 8]
mov edx, [ebp + 24]
or edx, edx
jnz @f
mov ecx, [eax + Vmem.size]
or ecx, ecx
jz @f
mov edx, [ebp - 4]
push dword [eax + Vmem.flags]
call vmem_add
add esp, 4
@@:
pop edi pop edi
pop esi pop esi
@ -448,14 +267,6 @@ vmem_destroy:
;; Out: ;; Out:
;; EAX - Allocated address on succes, 0 on failure. ;; EAX - Allocated address on succes, 0 on failure.
vmem_alloc: vmem_alloc:
push ecx
push dword VMEM_ADDR_MAX
push dword VMEM_ADDR_MIN
push dword 0
push dword 0
xor ecx, ecx
call vmem_xalloc
add esp, 20
ret ret
;; Function: vmem_free ;; Function: vmem_free
@ -479,231 +290,11 @@ vmem_free:
;; ESP[8] - Nocross. ;; ESP[8] - Nocross.
;; ESP[12] - Min address. ;; ESP[12] - Min address.
;; ESP[16] - Max address. ;; ESP[16] - Max address.
;; ESP[20] - Flags. (<VMEM_VM_BESTFIT>, <VMEM_VM_INSTANTFIT>, <VMEM_VM_SLEEP>, <VMEM_VM_NOSLEEP>) ;; ESP[20] - Flags. (<VM_BESTFIT>, <VM_INSTANTFIT>, <VM_NEXTFIT>, <VM_SLEEP>, <VM_NOSLEEP>)
;; ;;
;; Out: ;; Out:
;; EAX - Allocated address on succes, 0 on failure. ;; EAX - Allocated address on succes, 0 on failure.
vmem_xalloc: vmem_xalloc:
push ebp
mov ebp, esp
sub esp, 20
push esi
push edi
push ebx
mov esi, eax
mov edi, edx
mov ebx, ecx
; refill segment if needed
mov eax, [ebp + 24]
and eax, VMEM_VM_POPULATING
jz @f
cmp [iVmemFreeSegCount], VMEM_MIN_RESERVE
jg @f
call _vmem_refill
@@:
xor eax, eax
mov [ebp - 8], eax
mov [ebp - 4], eax
call _vmem_segalloc
or eax, eax
jz .fail
mov [ebp - 8], eax
call _vmem_segalloc
or eax, eax
jz .fail
mov [ebp - 4], eax
; set alignment to quantum if not set
or ebx, ebx
jnz @f
mov ebx, [esi + Vmem.quantum]
mov eax, [ebp + 24]
and eax, VMEM_VM_FIT_MASK
jz .fail ; TODO: error
.retry_strat:
; get freelist
mov edx, edi
VMEM_GET_LIST_FROM_SIZE edx, VMEM_FREELISTS_N
shl edx, 2
mov eax, esi
add eax, Vmem.freelist
add eax, edx
mov [ebp - 12], eax
.retry:
mov eax, [ebp + 24]
and eax, VMEM_VM_INSTANTFIT
jz .best_fit
; if not power of two use next
mov eax, edi
mov edx, eax
dec edx
and eax, edx
jz @f
add dword [ebp - 12], 4
@@:
mov eax, esi
add eax, Vmem.hashtable
cmp [ebp - 12], eax
jge .next
mov eax, [ebp - 12]
mov eax, [eax]
or eax, eax
jz .instant_fit_next
sub eax, VmemSegment.seglist
; save segment
mov [ebp - 16], eax
; block found
lea edx, [ebp - 20]
push edx ; &start
push dword [ebp + 20] ; maxaddr
push dword [ebp + 16] ; min addr
push dword [ebp + 12] ; nocross
push dword [ebp + 8] ; phase
mov edx, edi
mov ecx, ebx
call _vmem_segfit
add esp, 20
or eax, eax
jz .found
.instant_fit_next:
add dword [ebp - 12], 4
jmp @b
.best_fit:
; iterate each item in list
xchg bx, bx
mov eax, [ebp - 12]
.best_fit_loop:
mov eax, [eax]
or eax, eax
jz .best_fit_next
sub eax, VmemSegment.seglist
mov [ebp - 16], eax
cmp edi, [eax + VmemSegment.size]
jge @f
; block found
lea edx, [ebp - 20]
push edx ; &start
push dword [ebp + 20] ; maxaddr
push dword [ebp + 16] ; min addr
push dword [ebp + 12] ; nocross
push dword [ebp + 8] ; phase
mov edx, edi
mov ecx, ebx
call _vmem_segfit
add esp, 20
or eax, eax
jz .found
@@:
mov eax, [ebp - 16]
add eax, VmemSegment.seglist.next
jmp .best_fit_loop
.best_fit_next:
add dword [ebp - 12], 4
mov eax, esi
add eax, Vmem.hashtable
cmp [ebp - 12], eax
jl .best_fit
.next:
if 0
; NetBSD does this
; https://github.com/NetBSD/src/blob/trunk/sys/kern/subr_vmem.c#L1296-L1301
mov eax, [ebp + 24]
and eax, VMEM_VM_INSTANTFIT
jz @f
or eax, VMEM_VM_BESTFIT
mov edx, VMEM_VM_INSTANTFIT
not edx
and eax, edx
jmp .retry_strat
@@:
end if
; return error and free allocated segment if needed
.fail:
mov eax, [ebp - 8]
or eax, eax
jz @f
call _vmem_segfree
@@:
mov eax, [ebp - 4]
or eax, eax
jz @f
call _vmem_segfree
@@:
xor eax, eax
mov edx, ENOMEM
jmp .end
.found:
; remove seg from freelist
mov eax, [ebp - 16]
add eax, VmemSegment.seglist
call list_remove
; split left
mov eax, [ebp - 16]
mov eax, [eax + VmemSegment.base]
cmp eax, [ebp - 20]
je @f
mov edx, [ebp - 8]
mov dword [edx + VmemSegment.type], VMEM_SEGMENT_FREE
mov [edx + VmemSegment.base], eax
mov ecx, [ebp - 20]
sub ecx, eax
mov [edx + VmemSegment.size], ecx
mov eax, [ebp - 16]
mov dword [eax + VmemSegment.base], [ebp - 20]
mov edx, [eax + VmemSegment.size]
sub edx, ecx
mov [eax + VmemSegment.size], edx
; insert to freelist
VMEM_GET_LIST_FROM_SIZE ecx, VMEM_FREELISTS_N
shl ecx, 2
mov eax, esi
add eax, Vmem.freelist
add eax, ecx
mov edx, [ebp - 8]
add edx, VmemSegment.seglist
call list_insert_head
mov dword [ebp - 8], 0
@@:
; split right
.end:
pop ebx
pop esi
pop edi
pop ebx
leave
ret ret
;; Function: vmem_xfree ;; Function: vmem_xfree
@ -725,7 +316,7 @@ vmem_xfree:
;; EAX - Pointer to <Vmem> object. ;; EAX - Pointer to <Vmem> object.
;; EDX - Address. ;; EDX - Address.
;; ECX - Size in bytes. ;; ECX - Size in bytes.
;; ESP[4] - Flags. (<VMEM_VM_SLEEP> or <VMEM_VM_NOSLEEP>) ;; ESP[4] - Flags. (<VM_SLEEP> or <VM_NOSLEEP>)
;; ;;
;; Out: ;; Out:
;; EAX - Return Address on success, 0 on failure. ;; EAX - Return Address on success, 0 on failure.
@ -733,69 +324,22 @@ vmem_add:
push ebp push ebp
mov ebp, esp mov ebp, esp
if CONFIG_TRACE_VMEM push esi
sub esp, 12
mov [ebp - 12], eax
mov [ebp - 8], edx
mov [ebp - 4], ecx
end if
push edi push edi
; save flag to edi push ebx
mov edi, [ebp + 8]
push dword VMEM_SEGMENT_STATIC_SPAN mov esi, eax
push edi mov edi, ebx
call _vmem_add mov ebx, ecx
add esp, 8
pop ebx
pop edi pop edi
pop esi
if CONFIG_TRACE_VMEM
mov edx, [ebp - 8]
mov ecx, [ebp - 4]
add edx, ecx
TRACE szTraceVmemAdd, [ebp - 12], [ebp - 8], edx
end if
leave leave
ret ret
;; Function: vmem_size
;;
;; Return information about arenas size
;;
;; In:
;; EAX - Pointer to <Vmem> object.
;; EDX - Type mask.
;;
;; Out:
;; EAX - Free/allocated size in arena.
vmem_size:
xchg edx, eax
and eax, (VMEM_ALLOC or VMEM_FREE)
cmp eax, VMEM_ALLOC
jne @f
mov eax, [edx + Vmem.in_use]
ret
@@:
cmp eax, VMEM_FREE
mov eax, [edx + Vmem.size]
jne @f
mov edx, [edx + Vmem.in_use]
sub eax, edx
ret
@@:
ret
if CONFIG_TRACE_VMEM
;; Function: vmem_dump
;;
vmem_dump:
ret
end if
;; Function: vmem_bootstrap ;; Function: vmem_bootstrap
;; ;;
;; Initialize static segments ;; Initialize static segments
@ -817,28 +361,20 @@ end if
call _vmem_segfree call _vmem_segfree
add ebx, sizeof.VmemSegment add ebx, sizeof.VmSegment
cmp ebx, VMEM_STATIC_SEG_COUNT*sizeof.VmemSegment cmp ebx, STATIC_SEG_COUNT*sizeof.VmSegment
jl @b jl @b
pop ebx pop ebx
leave leave
ret ret
;;; MARK: Variables ;;; MARK: variables
;; Variable: aVmemStaticSegs aVmemStaticSegs db STATIC_SEG_COUNT*sizeof.VmSegment dup(0)
aVmemStaticSegs db VMEM_STATIC_SEG_COUNT*sizeof.VmemSegment dup(0)
;; Variable: pVmemFreeSegHead
pVmemFreeSegHead dd 0 pVmemFreeSegHead dd 0
;; Variable: iVmemFreeSegCount
iVmemFreeSegCount dd 0 iVmemFreeSegCount dd 0
szVmemSegmentAllocated db "allocated", 0
szVmemSegmentFree db "free", 0
szVmemSegmentSpan db "span", 0
;; Group: Debug
if CONFIG_TRACE_VMM if CONFIG_TRACE_VMM
szTraceVmemBootstrap db "Trace(VMEM): Bootstrap vmem", 0 szTraceVmemBootstrap db "Trace(VMEM): Bootstrap vmem", 0
szTraceVmemCreate db "Trace(VMEM): Create %s [%x, %x)", 0 szTraceVmemCreate db "Trace(VMEM): Create %s [%x, %x)", 0

View file

@ -113,10 +113,6 @@ tailq_insert_after:
ret ret
;; Function: tailq_insert_tail ;; Function: tailq_insert_tail
;;
;; In:
;; EAX - X
;; EDX - X
tailq_insert_tail: tailq_insert_tail:
ret ret