; *****************************************************************************
;
; MEM_INIT.ASM [ Initialization procs of TRDOS Memory Allocation & Management ]
; by Erdogan Tan, Last Update: 17/01/2010
; 13/06/2009, 14/07/2009, 22/08/2009, 21/09/2009, 25/10/2009 
;
; TRDOS.ASM (include mem_init.asm)
;
; *****************************************************************************

MEMAT_SEGMENT equ 50h

proc_memory_init   proc    near
                ; 25/10/2009 UMB allocation

                call proc_enable_A20_Line
                ; stc= Error, al=FFh
                ; cls= OK, al=0

                mov byte ptr [A20_Line_Enabled], al

		;  13/06/2009

                mov ax, MEMAT_SEGMENT
                mov es, ax
                xor di, di

                mov si, offset MEMAT_STR
                mov cx, 22
                rep movsb

                xor ax, ax  ; FREE
                mov cx, 1269
                rep stosw

               ; xor ch, ch

                mov ax, 0A0Ah
                mov cl, 128
                rep stosw
 
                mov ax, 0B0Bh
                mov cl, 128
                rep stosw

                mov ax, 0C0Ch
                mov cl, 128
                rep stosw

                mov ax, 0D0Dh
                mov cl, 128
                rep stosw

                mov ax, 0E0Eh
                mov cl, 128
                rep stosw

                mov ax, 0F0Fh
                mov cl, 128
                rep stosw
                
                mov al, byte ptr [A20_Line_Enabled]
                mov ah, al
                mov cx, 128
                rep stosw

                inc byte ptr [A20_Line_Enabled] 
 
                mov cx, KERNEL_FILESIZE
               
                xor bx, bx
                mov ax, 0101h  ; al= 01h, Kernel
                
                call proc_allocate_memory
                ;Return: BX= begin segment, DX= count of allocated units (100h bytes)
                ; CX= Allocation size, same value with CX input
                ; clc & AH= 0, no error, AL = Allocation type, same with input
                ; At the memory initialization time, any error return is not possible
                ; so, we can use return values directly, 
                ; without any error consideration.

                mov si, 100h
                mov es, bx
                xor di, di
                rep movsb

                mov cx, 100h
                xor bx, bx
                mov ax, 0102h ; AL= 2 : Kernel/System Stack
                call proc_allocate_memory

                ; Return: ES is new code segment of the Kernel
                
                retn

proc_memory_init endp
               
proc_allocate_memory proc near
                ; 17/01/2010
                ; 25/10/2009
		; 13/06/2009
                
                ; INPUT:
                ; CX= Allocation Size as bytes
                ; BX= Beginning Segment
                ; AH= 1 Allocate memory from beginning segment, consequently
                ; AL=Allocation Type
                ; OUTPUT:
                ; stc (cf is set) = Could not be allocated
                ; AH= Error number, CX= Allocation size, same as input
                ; AL= Allocation Type
                ; DX= Free consequent allocation units (100h bytes)
                ; clc (cf is reset) = Allocated, AH=0, no error
                ; CX and AL is not changed
                ; BX= is allocation segment and DX is count of alloc. units

                cmp ah, 1
                je short loc_allocate_consequent_units
                mov ah, 1 ; AH=1 -> ERR: Invalid calling type
                stc
                retn 

loc_allocate_consequent_units:  
                push cx
                mov byte ptr [Allocation_Type], al
                xor dx, dx
                mov ax, 256
                xchg ax, cx
                add ax, 255
                adc dx, 0
                div cx
                mov cx, ax  ; Count of allocation units
                mov ax, bx
                xor dx, dx
                add ax, 15 
                adc dx, 0
                push bx
                mov bx, 16
                div bx
                mov dx, cx  ; Count of allocation units
                pop bx
                push es
                push di
                push ds
                push si
                xor cx, cx
                mov si, MEMAT_SEGMENT
 		mov ds, si
                mov si, ax
loc_MEMAT_check_free_units_1:
                cmp si, 4351
                ja short pass_MEMAT_check_free_units  
                lodsb
                cmp al, 0
                ja short loc_MEMAT_check_free_units_1
                inc cx
                mov di, si
                dec di
                mov bx, di
                shl bx, 1
                shl bx, 1
                shl bx, 1
                shl bx, 1
                 ; bx= beginning segment
loc_MEMAT_check_free_units_2:
                cmp si, 4351
                ja short pass_MEMAT_check_free_units  
                lodsb
                ; 17/01/2010 bugfix
                ; cmp al, 0
                ; ja short pass_MEMAT_check_free_units  
                cmp al, 0
                ja short loc_MEMAT_check_free_units_3
                inc cx
                cmp cx, dx  ; Comparison for requested allocation size
                jb short loc_MEMAT_check_free_units_2

pass_MEMAT_check_free_units:
                mov ax, dx ; Count of requested allocation units
                mov dx, cx ; Count of free consequent allocation units
                cmp dx, ax
                jb short pass_allocate_counted_units
		push ds
                pop es 
                pop si
                pop ds
                mov al, byte ptr [Allocation_Type]
                rep stosb 
                pop di
                pop es               
                pop cx
                xor ah, ah
                retn 

loc_MEMAT_check_free_units_3:
                ; 17/01/2010 
                xor cx, cx
                jmp short loc_MEMAT_check_free_units_1

pass_allocate_counted_units:
                ; bx= beginning segment
 		pop si
                pop ds
                pop di
                pop es 
                mov al, byte ptr [Allocation_Type]
                pop cx
                mov ah, 2 ; Error -> Not enough consequent units
                stc
                retn   
 
MEMAT_STR: db 'MEMORYALLOCATIONTABLE', 16h 
Allocation_Type: db 0
A20_Line_Enabled: db 0

proc_allocate_memory endp


proc_enable_A20_line proc near
                ; Erdogan Tan, 11-6-2009
                ; INPUT: none
                ; OUTPUT:
                ; stc= Error, High Memory is not usable...
                ; AL=0 high memory (FFFF:0000 to FFFF:FFFF) is usable
                ; AL= FFh high memory is not usable
 
                ; Procedure origin: Erdogan Tan 30/12/2000 CENTRAL.ASM
          
enable_a20_line:
                mov  al, 0D1h
                out  64h, al

                xor cx, cx
loc_64h_in_al_1:
                in al, 64h
                and al, 2
                loopnz loc_64h_in_al_1
                jnz short return_from_enabling_A20_line_with_error

                mov al, 0DFh
                out 60h, al

               ;xor cx, cx
loc_64h_in_al_2:
                in al, 64h
                and al, 2
                loopnz loc_64h_in_al_2
                jnz short return_from_enabling_A20_line_with_error
                
                xor al, al    ; 11-6-2009
                retn          ; 11-6-2009
 
return_from_enabling_A20_line_with_error:
                mov al, 0FFh  ; 11-6-2009
                stc           ; 11-6-2009

                retn
       
proc_enable_A20_line endp


proc_deallocate_memory proc near
                ; 25/10/2009
		; 21/09/2009
                ; 17/07/2009
                
                ; INPUT:
                ; BX= Beginning Segment
                ; AH= 1 Deallocate memory from beginning segment, as consequtive
                ; AL= Allocation Type which will be deallocated
                ; OUTPUT:
                ; CX= Count of deallocated memory allocation units
                ; BX= The first segment which is deallocated 

                cmp ah, 1
                je short loc_deallocate_consequtive_units
                xor cx, cx
                retn 

loc_deallocate_consequtive_units:
                mov cx, bx
                shr cx, 1
                shr cx, 1
                shr cx, 1
                shr cx, 1   
                cmp cx, 22
                jnb short pass_deallocate_memory_fix_cx
                mov cx, 22
pass_deallocate_memory_fix_cx:
                push ds 
                push si
                mov si, MEMAT_SEGMENT
 		mov ds, si              
                mov si, cx
                xor cx, cx 
loc_check_allocation_unit_deallocated:  
                cmp si, 4351
                ja short loc_deallocate_consequtive_units_retn
                cmp byte ptr [SI], al
                je short loc_deallocate_current_memory_unit
                inc si 
                jmp short loc_check_allocation_unit_deallocated
loc_deallocate_current_memory_unit:
                mov bx, si
                shl bx, 1
                shl bx, 1
                shl bx, 1
                shl bx, 1
loc_loop_deallocate_current_memory_unit:
                mov byte ptr [SI], 0
                inc si
                inc cx
                cmp si, 4351
                ja short loc_deallocate_consequtive_units_retn
                cmp byte ptr [SI], al
                je short loc_loop_deallocate_current_memory_unit
loc_deallocate_consequtive_units_retn:
                pop si
                pop ds
                retn 

proc_deallocate_memory endp


proc_get_free_memory proc near
		; 25/10/2009
                ; INPUT:
                ; AX= Beginning Segment
                ; OUTPUT:
                ; AX= Total free allocation units (100h bytes)
                ; DX= Max. Free consequtive allocation units (100h bytes)
                ; CX= Total usable (conventional TRDOS) memory (100h bytes)
                ; BX= First free segment (valid if < FFFFh)
                ; cf= 1 -> no free memory

                push ds
               ;push si

                xor dx, dx
                mov word ptr [max_free_conseq_units], dx
                mov word ptr [free_memory_units], dx

                mov cx, 4096
                
               ;mov bl, byte ptr [A20_Line_Enabled]
               ;or bl, bl
               ;jz short pass_pgfm_add_high_memory_space 
               ;add cx, 256
                mov bh, byte ptr [A20_Line_Enabled]
                xor bl, bl
                add cx, bx                
;pass_pgfm_add_high_memory_space:

                push cx

                shr ax, 1
                shr ax, 1
                shr ax, 1
                shr ax, 1 
                
                sub cx, ax
                mov si, ax
            
                xor bx, bx
                dec bx  ; mov bx, 0FFFFh

                mov ax, MEMAT_SEGMENT
                mov ds, ax
    
loc_get_memat_allocation_unit_type:
                lodsb
                or al, al
                jnz short pass_pgfm_set_first_free_segment_1
                mov bx, si
                dec bx
                shl bx, 1
                shl bx, 1
                shl bx, 1
                shl bx, 1
                jmp short pass_pgfm_first_free_segment_2
 
pass_pgfm_set_first_free_segment_1:
                loop loc_get_memat_allocation_unit_type
                stc
                jmp short loc_pgfm_retn_1

loc_get_memat_allocation_unit_type_next:
                lodsb
                or al, al
                jnz short pass_pgfm_inc_free_count
pass_pgfm_first_free_segment_2:
                inc dx
                inc word ptr CS:[free_memory_units]
                loop loc_get_memat_allocation_unit_type_next
                cmp dx, word ptr CS:[max_free_conseq_units]
                jnb short loc_pgfm_retn_1
                clc 
                jmp short loc_pgfm_retn_0
pass_pgfm_inc_free_count:
                or dx, dx
                jz short pass_change_max_free_conseq_units_2  
                cmp dx, word ptr CS:[max_free_conseq_units]
                jna short pass_change_max_free_conseq_units_1
                mov word ptr CS:[max_free_conseq_units], dx
pass_change_max_free_conseq_units_1:                   
                xor dx, dx 
pass_change_max_free_conseq_units_2:
                loop loc_get_memat_allocation_unit_type_next
loc_pgfm_retn_0:
                mov dx, word ptr CS:[max_free_conseq_units]
loc_pgfm_retn_1:
                pop cx

               ;pop si
                pop ds
                
                mov ax, word ptr [free_memory_units]
                                        
                retn

max_free_conseq_units: dw 0
free_memory_units: dw 0

proc_get_free_memory endp
