Download src/xiaomao/xms.asm from HelloSun/dosllm: direct link, hf CLI and curl.
- Browser
- Download file 6.42 kB
-
https://huggingface.co/spaces/HelloSun/dosllm/resolve/main/src/xiaomao/xms.asm
- Command line
-
hf download hf://spaces/HelloSun/dosllm/src/xiaomao/xms.asm
-
curl -L -o xms.asm https://huggingface.co/spaces/HelloSun/dosllm/resolve/main/src/xiaomao/xms.asm
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. | |
| 16 | |
| _TEXT class=CODE | |
| xms_init_ | |
| xms_query_ | |
| xms_largest_ | |
| xms_total_ | |
| xms_alloc_ | |
| xms_free_ | |
| xms_move_ | |
| install_hooks_ | |
| save_vectors_ | |
| set_handlers_ | |
| is_installed_ | |
| bios_peek_ | |
| bios_getkey_ | |
| bios10_call_ | |
| get_rom_font_ | |
| 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: | |