dosllm / src /xiaomao /xms.asm
HelloSun's picture
小貓中文 v1.0 by HelloSun (2026-10-25): author attribution + GPLv3 section 7(b) term, startup notice, modified-version mark
aa96610 verified
Raw History Blame Contribute Delete
6.42 kB
; 小貓中文 - XMS helpers, interrupt stubs and BIOS wrappers
; Copyright (C) 2026 HelloSun
; Author: HelloSun First version: 1.0, 2026-10-25
; SPDX-License-Identifier: GPL-3.0-only
; Additional terms under GPLv3 section 7(b): the author attribution "HelloSun" and this copyright
; notice must be preserved in all copies and modified versions, including the notice the program
; displays when it starts. See LICENSE.
; See ../LICENSE for license terms.
;
; Watcom large model, register calling convention: args AX,DX,BX,CX; far return.
; Every helper preserves all registers except AX (return value).
; All variables live in the code segment so interrupt handlers never depend on DS.
bits 16
segment _TEXT public class=CODE
global xms_init_
global xms_query_
global xms_largest_
global xms_total_
global xms_alloc_
global xms_free_
global xms_move_
global install_hooks_
global save_vectors_
global set_handlers_
global is_installed_
global bios_peek_
global bios_getkey_
global bios10_call_
global get_rom_font_
global cpu_idle_
xms_entry: dd 0
xms_freekb: dw 0
xms_totalkb: dw 0
old16: dd 0
old10: dd 0
old2f: dd 0
c_key: dd 0
c_vid: dd 0
s_ss: dw 0
s_sp: dw 0
busy16: db 0
busy10: db 0
res10: dw 0
%macro SAVE 0
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
%endmacro
%macro REST 0
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
%endmacro
; ---------------------------------------------------------------- XMS
xms_init_:
SAVE
mov ax, 0x4310
int 0x2F
mov [cs:xms_entry], bx
mov [cs:xms_entry+2], es
REST
mov ax, 1
retf
xms_query_:
SAVE
mov ah, 0x08
call far [cs:xms_entry]
cld
mov [cs:xms_freekb], ax
mov [cs:xms_totalkb], dx
REST
retf
xms_largest_:
mov ax, [cs:xms_freekb]
retf
xms_total_:
mov ax, [cs:xms_totalkb]
retf
; unsigned xms_alloc(unsigned kb): returns handle or 0
xms_alloc_:
SAVE
mov dx, ax
mov ah, 0x09
call far [cs:xms_entry]
cld
cmp ax, 1
jne .fail
mov ax, dx
jmp .out
.fail:
xor ax, ax
.out:
REST
retf
xms_free_:
SAVE
mov dx, ax
mov ah, 0x0A
call far [cs:xms_entry]
cld
REST
retf
; unsigned xms_move(unsigned seg, unsigned off): move-struct at seg:off
xms_move_:
SAVE
mov si, dx
mov ds, ax
mov ah, 0x0B
call far [cs:xms_entry]
cld
REST
retf
; ---------------------------------------------------------------- BIOS helpers
; unsigned bios_peek(void): key (AX) of pending key or 0 when none
bios_peek_:
SAVE
mov ah, 1
pushf
call far [cs:old16]
jnz .have
xor ax, ax
.have:
REST
retf
; unsigned bios_getkey(void): wait for key
bios_getkey_:
SAVE
xor ah, ah
pushf
call far [cs:old16]
REST
retf
; unsigned bios10_call(unsigned ax, unsigned bx): call previous INT 10h, returns AX
bios10_call_:
push cx
push dx
push si
push di
push bp
push ds
push es
mov bx, dx ; second argument arrives in DX
pushf
call far [cs:old10]
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
retf
; void far *get_rom_font(void): ROM 8x16 font pointer (DX:AX), via INT 10h AX=1130h BH=6
get_rom_font_:
push bx
push cx
push si
push di
push bp
push ds
push es
mov ax, 0x1130
mov bx, 0x0600
int 0x10
mov ax, bp
mov dx, es
pop es
pop ds
pop bp
pop di
pop si
pop cx
pop bx
retf
; void cpu_idle(void): wait for next interrupt
cpu_idle_:
sti
hlt
retf
; void set_handlers(key_off, key_seg, vid_off, vid_seg)
set_handlers_:
mov [cs:c_key], ax
mov [cs:c_key+2], dx
mov [cs:c_vid], bx
mov [cs:c_vid+2], cx
retf
; unsigned is_installed(void)
is_installed_:
SAVE
mov ax, 0xD7A0
int 0x2F
cmp ax, 0x584D
mov ax, 0
jne .no
mov ax, 1
.no:
REST
retf
; void save_vectors(void): remember the previous INT 10h/16h/2Fh handlers
save_vectors_:
SAVE
mov ax, 0x3516
int 0x21
mov [cs:old16], bx
mov [cs:old16+2], es
mov ax, 0x3510
int 0x21
mov [cs:old10], bx
mov [cs:old10+2], es
mov ax, 0x352F
int 0x21
mov [cs:old2f], bx
mov [cs:old2f+2], es
REST
retf
; void install_hooks(void)
install_hooks_:
SAVE
push cs
pop ds
mov dx, int16_hook
mov ax, 0x2516
int 0x21
mov dx, int10_hook
mov ax, 0x2510
int 0x21
mov dx, int2f_hook
mov ax, 0x252F
int 0x21
REST
retf
; ---------------------------------------------------------------- INT 2Fh
int2f_hook:
cmp ax, 0xD7A0
jne .chain
mov ax, 0x584D
iret
.chain:
jmp far [cs:old2f]
; ---------------------------------------------------------------- INT 16h
int16_hook:
cmp ah, 0
je .mine
cmp ah, 1
je .mine
cmp ah, 0x10
je .mine
cmp ah, 0x11
je .mine
.chain:
jmp far [cs:old16]
.mine:
cmp byte [cs:busy16], 0
jne .chain
mov byte [cs:busy16], 1
SAVE
mov [cs:s_ss], ss
mov [cs:s_sp], sp
mov bx, cs
cli
mov ss, bx
mov sp, stack_top
sti
cld
call far [cs:c_key]
cli
mov ss, [cs:s_ss]
mov sp, [cs:s_sp]
sti
REST
mov byte [cs:busy16], 0
or ax, ax
retf 2
; ---------------------------------------------------------------- INT 10h
; The C handler receives a far pointer to the saved register frame
; (es ds bp di si dx cx bx ax ip cs flags) and returns 0 = handled, 1 = chain.
int10_hook:
cmp byte [cs:busy10], 0
jne .chain
mov byte [cs:busy10], 1
push ax
push bx
push cx
push dx
push si
push di
push bp
push ds
push es
mov [cs:s_ss], ss
mov [cs:s_sp], sp
mov ax, cs
cli
mov ss, ax
mov sp, stack_top
sti
cld
mov ax, [cs:s_sp]
mov dx, [cs:s_ss]
call far [cs:c_vid]
mov [cs:res10], ax
cli
mov ss, [cs:s_ss]
mov sp, [cs:s_sp]
sti
pop es
pop ds
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
mov byte [cs:busy10], 0
cmp word [cs:res10], 0
jne .chain
iret
.chain:
jmp far [cs:old10]
; private stack for interrupt work
stack:
times 2048 db 0
stack_top: