
%if 0

ReSizeable RAMDisk - assembly helpers
Copyright (C) 1992-1996, 2005 Marko Kohtala
Adapted from C source texts' inline assembly by E. C. Masloch, 2025
Released under GNU GPL, read the file 'COPYING' for more information

%endif

%include "lmacros3.mac"

%define c_disk_IO 2   ;/* Offset into disk_IO in config_s */
%define XMS_handle 0  ;/* Offsets into XMS_alloc structure */
%define XMS_entry 2
%define EMS_handle 0  ;/* Offsets into EMS_alloc structure */

bits 16		; nasm -felf defaults to bits 32

; ia16-gcc default calling convention:
; parameters in reverse order on stack (compared to lframe's)
; caller cleans the stack
; CHG (call clobbered): ax, bx, cx, dx
; Call preserved: si, di, bp, es
; STT (special): ds = ss
; OUT: al, ax, or dx:ax

%macro entry 1.nolist
	global %1
%1:
%endmacro


; extern byte far * getlistoflists(void);

entry getlistoflists
	push es
	mov ah, 52h
	int 21h
	xchg ax, bx
	mov dx, es
	pop es
	retn


; extern word asm_xfer_sector
;  (char rw, int count, dword start, void far * buffer, void far * function);

entry asm_xfer_sector
	lframe near
	lpar dword, function
	lpar dword, buffer
	lpar dword, start
	lpar word, count
	lpar word, rw
	lenter
    push es
    push si
    push di
    push word [bp + ?rw]
    push word [bp + ?count]
    push word [bp + ?start+2]
    push word [bp + ?start]
    push word [bp + ?buffer+2]
    push word [bp + ?buffer]
    call far [bp + ?function]
     times 6 pop di		; "add sp, 12" without clobering CF
				; bug in SRDISK v2.09
    pop di
    pop si
    pop es
     push ss
     pop ds
    jnc .done
    mov ax, -1
.done:
	lleave
	retn


; extern dword asm_freemem(void far * function);

entry asm_freemem
	lframe near
	lpar dword, function
	lenter
    push es
    push si
    push di
    call far [bp + ?function]	; dx:cx = return
    xchg ax, cx			; put it into dx:ax
    pop di
    pop si
    pop es
     push ss
     pop ds
	lleave
	retn


; extern word asm_query_drive(byte drive);

entry asm_query_drive
	lframe near
	lpar word, drive
	lenter
        mov ax,0x4409
        mov bl,byte [bp + ?drive]
        sub bl,'A'-1
        jc .no_fix       ;/* Bad drive letter */
        int 0x21
        jc .no_fix       ;/* Failed access drive */
        test dh,0x80
        jnz .no_fix      ;/* SUBSTed drive */
        mov dl, [bp + ?drive]
        sub dl,'A'-1
        mov ah,0x1C     ;/* Get Drive Data */
        int 0x21
         push ss
         pop ds
        mov ax, 1		; return true
        db __TEST_IMM16		; skip xor
.no_fix:
	xor ax, ax		; return false
	lleave
	retn


; extern byte free_ems_handle(word handle);

entry free_ems_handle
	lframe near
	lpar word, handle
	lenter
    mov dx, [bp + ?handle]
    mov ah,0x45  ;/* Free expanded memory block */
    int 0x67
    mov al, ah
	lleave
	retn


; extern byte alloc_ems_handle(void far * allocs, word pages);

entry alloc_ems_handle
	lframe near
	lpar word, pages
	lpar dword, allocs
	lenter
    mov bx, word [bp + ?pages]
    mov ah,0x43      ;/* Allocate */
    int 0x67
    mov al, ah
    test al, al
    jnz .fail
    lds bx, [bp + ?allocs]
    mov word [bx + EMS_handle], dx
    push ss
    pop ds
.fail:
	lleave
	retn


; extern word realloc_ems_handle(void far * allocs, word * pages);

entry realloc_ems_handle
	lframe near
	lpar word, indirectpages
	lpar dword, allocs
	lenter
    mov bx, [bp + ?indirectpages]
     push word [bx]
    lds bx, [bp + ?allocs]
    mov dx, [bx + EMS_handle]
     pop bx
    push ss
    pop ds
    mov ah,0x51      ;/* Reallocate */
    int 0x67
    mov al, ah
%if 0	; bug in SRDISK v2.09
    mov ah, bl			; error code if al != 0
%endif
    test al, al
    jnz .error			; bug? in SRDISK v2.09
    push bx
    mov bx, word [bp + ?indirectpages]
    pop word [bx]
.error:
	lleave
	retn


; extern byte copy_ems(void far * pmb);

entry copy_ems
	lframe near
	lpar dword, pmb
	lenter
    mov ax,0x5700
    push ds
    push si
    lds si, [bp + ?pmb]
    int 0x67
    pop si
    pop ds
    mov al, ah
	lleave
	retn


; extern dword ems_available(void);

entry ems_available
    mov ah,0x42
    int 0x67
    mov ax,16
    mul bx			; dx:ax = amount KiB available
	retn


; extern byte check_windows(void);

entry check_windows
      mov ax,0x1600
      int 0x2f
      and al,0x7f
      jz .not
      mov al, 1
.not:
	retn


; extern byte check_xms_3(void far * allocs);

entry check_xms_3
	lframe near
	lpar dword, allocs
	lvar dword, entry
	lenter
      mov ah,0      ;/* GET VERSION */
      lds bx, [bp + ?allocs]
      call far [bx + XMS_entry]
      push ss
      pop ds
      cmp ax,0x300
      jb .noSuperXMS

;/* From CPUID by Intel. Some HIMEM.SYS v3.0 functionality crash with 286.
;
;       This procedure determines the type of CPU in a system
;       and sets the cpu_type variable with the appropriate
;       value.
;       All registers are used by this procedure, none are preserved.
;
;       Intel 8086 CPU check
;       Bits 12-15 of the FLAGS register are always set on the
;       8086 processor.
;*/
        pushf
        pushf                   ;/* push original FLAGS */
        pop     ax              ;/* get original FLAGS */
        mov     cx, ax          ;/* save original FLAGS */
        and     ax, 0xfff       ;/* clear bits 12-15 in FLAGS */
        push    ax              ;/* save new FLAGS value on stack */
        popf                    ;/* replace current FLAGS value */
        pushf                   ;/* get new FLAGS */
        pop     ax              ;/* store new FLAGS in AX */
        popf
        and     ax, 0xf000      ;/* if bits 12-15 are set, then CPU */
        cmp     ax, 0xf000      ;/*   is an 8086/8088 */
        je      .noSuperXMS      ;/* jump if CPU is 8086/8088 */

;/*       Intel 286 CPU check */
;/*       Bits 12-15 of the FLAGS register are always clear on the */
;/*       Intel 286 processor in real-address mode. */

        pushf
        or      cx, 0xf000      ;/* try to set bits 12-15 */
        push    cx              ;/* save new FLAGS value on stack */
        popf                    ;/* replace current FLAGS value */
        pushf                   ;/* get new FLAGS */
        pop     ax              ;/* store new FLAGS in AX */
        popf
        and     ax, 0xf000      ;/* if bits 12-15 clear, CPU=80286 */
        jz      .noSuperXMS      ;/* if no bits set, CPU is 80286 */

subcpu 386

      ;/* Query free extended to see if SuperXMS really supported */
      mov ah,0x88   ;/* QUERY FREE (32-bit) */
      lds bx, [bp + ?allocs]
      lds bx, [bx + XMS_entry]
      mov word [bp + ?entry], bx
      mov word [bp + ?entry + 2], ds
      xor bx, bx
      push eax
      push ecx
      push edx
      call far [bp + ?entry]
      pop edx
      pop ecx
      pop eax
      cmp bl,0x80  ;/* Not Implemented - not a 32-bit system */
      push ss
      pop ds
      je .noSuperXMS

subcpureset
	mov al, 1
	db __TEST_IMM16		; skip mov
.noSuperXMS:
	mov al, 0
	lleave
	retn


; extern byte get_xms_handle_size(void far * allocs, dword * size, byte hasxms3);

entry get_xms_handle_size
	lframe near
	lpar word, hasxms3
	lpar word, indirectsize
	lpar dword, allocs
	lenter
      lds bx, [bp + ?allocs]
      mov dx, [bx + XMS_handle]
      cmp byte [bp + ?hasxms3], 0
      ja .xms3		; this condition was inverted in SRDISK v2.09
.xms2:
      mov ah,0xE      ;/* Get handle information */
      call far [bx + XMS_entry]
      push ss
      pop ds
	test ax, ax
	jz .fail
	mov bx, word [bp + ?indirectsize]
	mov word [bx], dx
	jmp .done

.xms3:
subcpu 386
	push edx
      mov ah,0x8E     ;/* Get 32bit handle information */
      call far [bx + XMS_entry]
      push ss
      pop ds
	test ax, ax
	jz .fail_edx
	mov bx, word [bp + ?indirectsize]
	mov dword [bx], edx
	pop edx
.done:
	mov al, -1
	jmp .ret

.fail_edx:
	pop edx
subcpureset

.fail:
	mov al, 0
.ret:
	lleave
	retn


; extern word free_xms_handle(void far * allocs, word handle);

entry free_xms_handle
	lframe near
	lpar word, handle
	lpar dword, allocs
	lenter
      lds bx, [bp + ?allocs]
      mov dx, [bp + ?handle]
      mov ah,0xA  ;/* Free extended memory block */
      call far [bx + XMS_entry]
      push ss
      pop ds
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .fail
        xor ax, ax
.fail:
	lleave
	retn


; extern word alloc_xms3_handle(void far * allocs, dword size);

entry alloc_xms3_handle
	lframe near
	lpar dword, size
	lpar dword, allocs
	lenter
subcpu 386
	 push edx
	 pop dx
        mov ah,0x89   ;/* Allocate 32-bit */
        mov edx, [bp + ?size]
        lds bx, [bp + ?allocs]
        call far [bx + XMS_entry]
         push dx
         pop edx
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .ret
        mov [bx + XMS_handle], dx
        xor ax, ax
.ret:
	push ss
	pop ds
subcpureset
	lleave
	retn


; extern word alloc_xms2_handle(void far * allocs, dword size);

entry alloc_xms2_handle
	lframe near
	lpar dword, size
	lpar dword, allocs
	lenter

	mov ah,0x9      ;/* Allocate */
        mov dx, [bp + ?size]
        lds bx, [bp + ?allocs]
        call far [bx + XMS_entry]
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .ret
        mov [bx + XMS_handle], dx
        xor ax, ax
.ret:
	push ss
	pop ds

	lleave
	retn


; extern word realloc_xms3_handle(void far * allocs, dword size);

entry realloc_xms3_handle
	lframe near
	lpar dword, size
	lpar dword, allocs
	lenter
subcpu 386
	push si
	 push ebx
	 pop bx
        mov ah,0x8F   ;/* Reallocate 32-bit */
        mov ebx, [bp + ?size]
        lds si, [bp + ?allocs]
        mov dx, [si + XMS_handle]
        call far [si + XMS_entry]
         push bx
         pop ebx
        pop si
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .ret
        xor ax, ax
.ret:
	push ss
	pop ds
subcpureset
	lleave
	retn


; extern word realloc_xms2_handle(void far * allocs, dword size);

entry realloc_xms2_handle
	lframe near
	lpar dword, size
	lpar dword, allocs
	lenter
	push si
	mov ah,0xF      ;/* Reallocate */
        mov bx, [bp + ?size]
        lds si, [bp + ?allocs]
        mov dx, [si + XMS_handle]
        call far [si + XMS_entry]
        pop si
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .fail
        xor ax, ax
.fail:
	push ss
	pop ds
	lleave
	retn


; extern word copy_xms(void far * allocs, void far * pmb);

entry copy_xms
	lframe near
	lpar dword, pmb
	lpar dword, allocs
	lenter
    mov ah,0xB
    push si
    push es
    push di
    lds si, [bp + ?pmb]
    les di, [bp + ?allocs]
    call far [es:di + XMS_entry]
    pop di
    pop es
    pop si
        test ax, ax
	mov al, -1
	mov ah, bl
        jz .fail
        xor ax, ax
.fail:
	push ss
	pop ds
	lleave
	retn


; extern byte get_xms3_available(void far * allocs, dword * size);

entry get_xms3_available
	lframe near
	lpar word, indirectsize
	lpar dword, allocs
	lvar dword, entry
	lenter
      lds bx, [bp + ?allocs]
      lds bx, [bx + XMS_entry]
      mov word [bp + ?entry], bx
      mov word [bp + ?entry + 2], ds
      xor bx, bx
subcpu 386
	push eax
	push ecx
	push edx
      mov ah,0x88
      call far [bp + ?entry]
      push ss
      pop ds
	test bl, bl
	jz .ok
	xor eax, eax
.ok:
	mov bx, word [bp + ?indirectsize]
	mov dword [bx], eax
	pop edx
	pop ecx
	pop eax
subcpureset
	lleave
	retn


; extern byte get_xms2_available(void far * allocs, dword * size);
	; INP:	*size is pre-initialised to zero

entry get_xms2_available
	lframe near
	lpar word, indirectsize
	lpar dword, allocs
	lvar dword, entry
	lenter
      lds bx, [bp + ?allocs]
      lds bx, [bx + XMS_entry]
      mov word [bp + ?entry], bx
      mov word [bp + ?entry + 2], ds
      xor bx, bx
      mov ah, 8
      call far [bp + ?entry]
      push ss
      pop ds
	test bl, bl
	jz .ok
	xor ax, ax
.ok:
	mov bx, word [bp + ?indirectsize]
	mov word [bx], ax
	lleave
	retn


; extern dword asm_call_alloc(void far * function, dword size);

entry asm_call_alloc
	lframe near
	lpar dword, size
	lpar dword, function
	lenter
	 push es
	 push di
	 push si
	push word [bp + ?size + 2]
	push word [bp + ?size]
	call far [bp + ?function]
	 pop si
	 pop di
	 pop es
	push ss
	pop ds
	lleave
	retn
