⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 manager.asm

📁 独立 WIN98下磁盘分区程序(C语言+汇编) 界面功能类似FDISK 但独立编译
💻 ASM
📖 第 1 页 / 共 3 页
字号:
.MODEL LARGE
ASSUME	CS:ADV_MAN_TEXT, DS:BOOT_DATA, ES:BOOT_DATA, SS:BOOT_DATA
PUBLIC _ADV_IPL, _ADV_MANAGER, _encrypt_password
LOCALS

SECT_SIZE	EQU	  512

MAX_MENU_ROWS	EQU	   16
MAX_PART_ROWS	EQU	   32

ADV_CODE_SIZE	EQU	 8192
ADV_DATA_SIZE	EQU	 2048

ADV_CODE_SECT	EQU	(ADV_CODE_SIZE/SECT_SIZE)
ADV_DATA_SECT	EQU	(ADV_DATA_SIZE/SECT_SIZE)

ADV_CODE_ADDR	EQU	(800h)
ADV_DATA_ADDR	EQU	(800h+ADV_CODE_SIZE)

ADV_MAGIC_VALUE	EQU	0ABCDh

ADV_OPT_VIR_CHECK	EQU	1
ADV_OPT_CLEAR_SCR	EQU	2
ADV_OPT_DEF_MENU	EQU	4
ADV_OPT_IGN_UNUSED	EQU	8

OS_HIDDEN	EQU	0FF80h
OS_ADV		EQU	0FF81h
OS_UNKN		EQU	0FFFFh

M_BOOT_EMPTY	EQU	0
M_BOOT_PART	EQU	1
M_BOOT_NEXT_HD	EQU	2
M_BOOT_FLOPPY	EQU	3

SHOW_ONE	EQU	0
SHOW_LAST	EQU	1
SHOW_NEXT	EQU	2
SHOW_PREV	EQU	3
SHOW_LAST3	EQU	4

M_OPT_PASSW	EQU	1

INCLUDE COLORS.INC

	X	EQU	30
	Y	EQU	2
	W	EQU	50
;	H	EQU	16

	KEYS_X	EQU	(X+4)
;	KEYS_Y	EQU	(Y+H-2)
	KEYS_W  EQU	(31+12)

	DOT_X	EQU	(KEYS_X+11)
	DOT_Y	EQU	(KEYS_Y)
	DOT_NUM	EQU	(31)


	DOT1	EQU	07h
	DOT2	EQU	0FAh

TITLE_COLOR	EQU	Yellow+BakBlack
MENU_COLOR	EQU	BrWhite+BakBlack
ACTIVE_COLOR	EQU	Black+BakCyan
KEYS_KEY_COLOR	EQU	Yellow+BakBlack
KEYS_TXT_COLOR	EQU	BrCyan+BakBlack
BORDER_COLOR	EQU	BrGreen+BakBlack	; Yellow+BakBlue
DOTBAR_COLOR	EQU	BrWhite+BakBlack


BOOT_DATA	SEGMENT	AT 0h

		ORG 600h

MBR_SECT	DB 	512 Dup(?)

		ORG 7B0h

ADV_REL_SECT	DD	?
ADV_RESERVED	DD	?
adv_act_menu	DB	?
adv_boptions	DB	?
adv_abmmagic	DB	4 Dup(?)

mbr_part_rec	STRUC		; 16 bytes
  b_boot_flag	DB	?
  b_chs_start	DB	3 Dup(?)
  b_os_id	DB	?
  b_chs_end	DB	3 Dup(?)
  b_rel_sect	DD	?
  b_num_sect	DD	?
ENDS

part_rec	mbr_part_rec 	4 DUP(?)

		ORG	ADV_DATA_ADDR

ADV_SIGNATURE	DB	15 Dup(?) ; "AdvBootManager",0
ADV_VERSION	DB	?
adv_def_menu	DB	?
adv_timeout	DB	?
adv_options	DB	?
adv_options2	DB	?
adv_password	DW	?
adv_reserved2	DB	26 Dup(?)
adv_title	DB	32 Dup(?)

adv_menu_rec	STRUC			; 80 bytes
  m_type	DB	 ?
  m_options	DB	 ?
  m_name	DB	30 Dup(?)
  m_tag		DB	 ?
  m_show	DB	 ?
  m_reserved	DB	14 Dup(?)
  m_num_keys	DW	 ?
  m_keys    	DW	15 Dup(?)
ENDS

adv_part_rec	STRUC			; 16 bytes
  p_os_id	DW	?
  p_tag		DB	?
  p_orig_row	DB	?
  p_reserved	DB	4 Dup(?)
  p_rel_sect	DD	?
  p_num_sect	DD	?
ENDS

menu		adv_menu_rec	MAX_MENU_ROWS  Dup(?)
part		adv_part_rec	MAX_PART_ROWS  Dup(?)

		ORG	ADV_DATA_ADDR + ADV_DATA_SIZE

NUM_DISKS	DB	?
DISK		DB	?
DISK_NUM_CYLS	DW	?
DISK_NUM_HEADS	DW	?
DISK_NUM_SECTS	EQU	SECT_PER_TRACK
SECT_PER_CYL	DW	?
SECT_PER_TRACK	DW	?

_ScreenArea	DD   ?	; B800h:0000h
_ScreenWidth	DB   ?	;  80
_ScreenHeight	DB   ?	;  25
_ScreenLength	DW   ?	; 80*25

NUM_MENUS	DW	?
ACT_MENU	DW	?
MENU_PTR	DW	MAX_MENU_ROWS Dup(?)
PART_PTR	DW	MAX_MENU_ROWS Dup(?)

ACT_MBR_REC	DW	?
ACT_PART_PTR	DW	?
PART_TMP	adv_part_rec	4 Dup(?)
PART_TMP2	adv_part_rec	?
MBR_SECT_BAK	DB	512 Dup(?) 

TMP		DB	  80 Dup(?)
SAV_BUFFER	DB	4096 Dup(?)
SAV_BUFFER_ERR	DB	 640 Dup(?)
CURSOR_SAVE_XY	DW	?
TICKS_PER_DOT	DW	?
H		DB	?
KEYS_Y		DB	?
PASS_VALIDATED	DW	?
FILL_KB_BUFFER	DW	?
ALT_ENTER	DW	?
LAST_PART	DW	?
IMPORTED_FLAG	DW	?
FD_PARAMS	DB	4 Dup(?)


STACK_AREA	DB	1024	Dup(?)	; Reserving at list 1k for stack

		ORG	7C00h
		
OS_BOOT_SECT	DB	SECT_SIZE Dup(?)


BOOT_DATA	ENDS


;----------------------------------------------------------------------
PUSH_REGS	MACRO
		push	ax
		push	bx
		push	cx
		push	dx
		push	di
		push	si
		push	ds
		push	es
ENDM
;----------------------------------------------------------------
POP_REGS	MACRO
		pop	es
		pop	ds
		pop	si
		pop	di
		pop	dx
		pop	cx
		pop	bx
		pop	ax
ENDM
;----------------------------------------------------------------

ADV_MAN_TEXT	SEGMENT	PARA PRIVATE	'CODE'

		mov	ax, cs
		mov	ds, ax
		mov	es, ax
		mov	ss, ax
		mov	sp, 7C00h
		xor	cx, cx
		mov	dl, 80h
		mov	Word Ptr ADV_REL_SECT, 7
		mov	Word Ptr ADV_REL_SECT+2, 0
		jmp	debug_entry

		ORG	600h

_ADV_IPL	PROC	NEAR
		;
		;  BIOS loads MBR at 0000:7C00h
		;
		;  Lets move code to 0000:0600h
		;
		xor	ax, ax
		mov	ds, ax
		mov	es, ax
		mov	ss, ax	;  CPU clears interrupt flag for next command
		mov	sp, 7C00h
		cld
		mov	si, sp
		mov	di, 0600h
		mov	cx, 0100h
		rep
		 movsw
	;	jmp	0000:@@ENTRY
		DB	0EAh
		DW	(@@ENTRY-_ADV_IPL+600h), 0000
		;
		;
ErrBootMan	EQU	(@@M1-_ADV_IPL+600h)
BootAorHD	EQU	(@@M2-_ADV_IPL+600h)
ErrBootSct	EQU	(@@M3-_ADV_IPL+600h)
MsgNL		EQU	(@@M4-_ADV_IPL+600h)
		;
@@M1:		DB "Cannot load Boot Manager.",0Dh,0Ah
@@M2:		DB "Boot from A or hard disk? ",0
@@M3:		DB "Error reading Boot Sector."
@@M4:		DB 0Dh,0Ah,0
		;
ADV_CODE_CHECK_SUM	DW	0
		;
debug_entry:
@@ENTRY:
;GET_DISK_INFO	PROC	NEAR
		;
		;  dl - disk number
		;
		cmp	dl, 80h
		jae	@@skip
		mov	dl, 80h
@@skip:
		mov	DISK, dl
		mov	cl, 3
@@get_again:
		mov	ah, 08		; Get disk parameters
		int	13h
		jnc	@@eval
		mov	ah, 0
		int	13h
		loop	@@get_again
		jmp	@@err1		; Error
@@eval:
;		mov	NUM_DISKS, dl
		xor	ah, ah
		mov	al, dh
		inc	ax		; AX - Number of HEADS (SIDES)
		mov	DISK_NUM_HEADS, ax 
		xor	bh, bh
		mov	bl, cl
		and	bl, 3Fh		; BX - Number of SECTORS / TRACK
		mul	bx
		mov	SECT_PER_CYL, ax
		mov	SECT_PER_TRACK, bx

		mov	bl, ch
		shl	cx, 1
		shl	cx, 1
		and	ch, 3
		mov	bh, ch
		inc	bx
		mov	DISK_NUM_CYLS, bx
;GET_DISK_INFO	ENDP
		;
		;	Read Advanced Boot Manager Data and Code
		;
		mov	ax, Word Ptr ADV_REL_SECT
		mov	dx, Word Ptr ADV_REL_SECT+2

		mov	bx, ADV_DATA_ADDR
		mov	cx, ADV_DATA_SECT
		
		call	READ_N_SECT
		jc	@@err1
		
		add	ax, ADV_DATA_SECT
		adc	dx, 0

		mov	bx, ADV_CODE_ADDR
		mov	cx, ADV_CODE_SECT

		call	READ_N_SECT
		jc	@@err1

		cmp	[bx], ADV_MAGIC_VALUE
		jne	@@err1
		;
		jmp	adv_code_entry_point
	;	jmp	0000h:0800h		; Jump to Boot Manager
	;	DB	0EAh
	;	DW	0800h,0000h
		;
bad_boot_man:
@@err1:
		mov	si, ErrBootMan
@@err2:
		call	PRINT
		mov	ah, 0
		int	16h		;  Get a key
		mov	si, MsgNL
		call	PRINT
		cmp	al, 'A'
		je	@@floppy	;  Boot from floppy
		cmp	al, 'a'
		je	@@floppy
		;
		;  Find active partition on hard disk
		;
@@part_tab:
		mov	cx, 4
		mov	di, 7BEh		; Address of the first record
@@next_part:
		cmp	Byte Ptr [di], 00
		jnz	@@read_hd		; Active partition found
		add	di, 10h
		loop	@@next_part
@@floppy:					; No active partition found
		xor	dx, dx
		;mov	dx, 0000		; Lets boot from floppy
		mov	cx, 0001
		jmp	@@read_sect
@@read_hd:
		mov	dx, [di]
		mov	cx, [di+2]
@@read_sect:
		mov	bx, 7C00h
		call	READ_SECT
		jnc	@@go_boot
		;
		mov	si, ErrBootSct
		call	PRINT
		mov	si, BootAorHD
		jmp	@@err2
		;
@@go_boot:
		mov	dl, [di]	; Boot sector expects Drive# in DL
	;	jmp	0000h:7C00h	; Transfer control to loaded BootSector
		DB	0EAh
		DW	7C00h,0000h
		;
		;
		;
REL_SECT_TO_CHS	PROC	NEAR
		;
		;  Input:    DX:AX - relative sector
		;  Output:   DH,CX - CHS and DL - disk
		;  Destroys: AX
		;
		div	SECT_PER_CYL		; AX=CYL, DX=SECT on CYL
		mov	cx, ax
		shr	cx, 1
		shr	cx, 1
		and	cl, 0C0h
		mov	ch, al
		mov	ax, dx
		xor	dx, dx
		div	SECT_PER_TRACK		; AX=HEAD, DX=SECT
		mov	dh, al
		inc	dl
		and	dl, 3Fh
		or	cl, dl
		mov	dl, DISK
		ret
REL_SECT_TO_CHS	ENDP
		;
		;
READ_N_SECT	PROC	NEAR
		;
		;
		;	ES:BX - Destination address
		;	DX:AX - Relative sector on disk
		;	CX    - Number of sectors to read
		;
		;	Returns: Flag CF set if error
		;
		push	ax
		push	bx
		push	cx
		push	dx
@@next_sect:
		push	ax
		push	cx
		push	dx
		call	REL_SECT_TO_CHS
		call	READ_SECT
		pop	dx
		pop	cx
		pop	ax
		jc	@@end

		add	ax, 1
		adc	dx, 0

		add	bx, SECT_SIZE

		loop	@@next_sect
@@end:
		pop	dx
		pop	cx
		pop	bx
		pop	ax
		ret
READ_N_SECT	ENDP
		;
		;
		;
READ_SECT	PROC	NEAR
		;
		;   ES:BX - Address
		;   CX,DX - CHS
		;
		;   Returns: CF set if error
		;
		push	si
		mov	si, 3		; We will try at most three times
@@try_again:
		mov	ax, 0201h	; Read (AH=02) 1 Sector (AL=01)
		int	13h
		jnc	@@end
					; We get here if there was an error
		mov	ah, 0		; We will try to reset device
		int	13h
	
		dec	si
		jnz	@@try_again
		;
		; We have tried three times, so we will give up
		;
		stc
	@@end:
		pop	si
		ret
READ_SECT	ENDP
		;
		;
PRINT		PROC	NEAR
		;
		;  ds:si - address of null terminated string to print
		;
		push	ax
		push	bx
		push	si
		mov	ah, 0Eh
		mov	bh, 00h
@@pr1:
		lodsb
		or	al, al
		jz	@@pr2
		int	10h
		jmp	@@pr1
@@pr2:
		pop	si
		pop	bx
		pop	ax
		ret
PRINT		ENDP
		;
		;
GAP1		PROC
GAPLEN1		EQU	(01B0h-(GAP1-_ADV_IPL))
IF GAPLEN1
		DB	GAPLEN1 DUP(0)	
ENDIF
GAP1		ENDP

ADV_MBR_MISC	DB	14+64+2 Dup(0)

_ADV_IPL	ENDP
		;
		;
		;
		;
_ADV_MANAGER	PROC	NEAR
		;
		;  IPL loads MANAGER at 0000h:0800h = 0800h
		;
		;               SS:SP = 0000h:7C00h = 7C00h
		;
ADV_MAGIC_NUM	DW	ADV_MAGIC_VALUE
		;
adv_code_entry_point:
		;
		;  First of all lets check integrity of code
		;
CHECK_CODE_INTEGRITY	PROC	NEAR
		xor	bx, bx
		mov	cx, ADV_CODE_SIZE
		shr	cx, 1
		mov	si, ADV_CODE_ADDR
@@add_next_word:
		lodsw
		add	bx, ax
		loop	@@add_next_word
		cmp	ADV_CODE_CHECK_SUM, 0
		je	@@initialize_sum
		cmp	ADV_CODE_CHECK_SUM, bx
		je	@@check_data_header
		jmp	bad_boot_man
@@initialize_sum:
		mov	ADV_CODE_CHECK_SUM, bx
@@check_data_header:
		mov	cx, 15
		lea	si, ADV_SIGNATURE
		lea	di, ADV_SIGNATURE2
		repe
		  cmpsb
		je	@@data_header_valid
		jmp	bad_boot_man
@@data_header_valid:
CHECK_CODE_INTEGRITY	ENDP
		;
CHECK_INTERRUPT_VECTORS	PROC
		test	adv_options, ADV_OPT_VIR_CHECK
		jz	@@ints_okay
		mov	cx, 1Dh			;  Check interrupts 0h to 1Ch
		mov	bx, 3
@@next_int:
		cmp	byte ptr [bx], 0C0h	;  They must be >= C000:0000h
		jb	@@int_changed
		add	bx, 4
		loop	@@next_int

		mov	bx, 4Ah*4-1		; int 4Ah - User Alarm
		cmp	byte ptr [bx], 0C0h
		jb	@@int_changed

		mov	bx, 70h*4-1		; int 70h - Real-Time Clock
		cmp	byte ptr [bx], 0C0h
		jb	@@int_changed
		
		jmp	@@ints_okay
@@int_changed:
		lea	si, VirusWarning
		call	PRINT
@@wait_enter:
		mov	ah, 0
		int	16h		;  Get a key
		cmp	al, 0Dh
		jne	@@wait_enter	;  And loop until ENTER is pressed
		lea	si, VirusNL
		call	PRINT
@@ints_okay:
CHECK_INTERRUPT_VECTORS	ENDP
		;
		;
		jmp	@@start
		;
		;   Messages
		;
ADV_SIGNATURE2	DB  "AdvBootManager",0
Border		DB  "赏缓 喝图"
Border1		DB  "谀砍 忱馁"
Mesg_OK		DB  " OK ",0
BottomKeysESC	DB  "ESC",0
BottomKeysText	DB  "ESC - Boot",0
BottomKeysEnt	DB  "Enter",0
BottomKeysText2	DB  "Press Enter to boot from selected partition",0
MesgSetTimeout	DB  "Select menu timeout (+/-): ",0
MesgErrorRead	DB  "Error reading boot sector",0
MesgErrorSave	DB  "Error saving MBR to disk",0
MesgErrorSaveAdv DB "Error saving Advanced MBR to disk",0
MesgEnterPassword DB "Enter password:",0
MesgPasswordInvalid DB "Password invalid",0
MesgBootInvalid	DB  "Boot sector is invalid",0
MesgImported	DB  "One or more partitions was changed in MBR. Please, run PART.EXE",0
VirusWarning	DB  0Dh, 0Ah
		DB  "One or more interrupts does not point to BIOS.", 0Dh, 0Ah
		DB  "This may be a sign of a stealth boot virus.", 0Dh, 0Ah
		DB  "Turn the computer OFF then ON and run antivirus.", 0Dh, 0Ah
		DB  "Or press ENTER to continue booting... ", 0
VirusNL		DB  0Dh, 0Ah, 0
		;
		;
@@start:
		call	_conio_init
		call	CHECK_LAST_CYL
		call	IMPORT_NEW_PART
		call	PREP_MENU_LIST
		call	BACKUP_MBR_SECT

	@@menu:
		mov	ax, NUM_MENUS
		add	ax, 6
		mov	H, al
		add	al, Y
		sub	al, 2
		mov	KEYS_Y, al

		mov	PASS_VALIDATED, 0
		
		call	INIT_SCREEN
		call	MAIN_MENU
		call	DONE_SCREEN
		
		cmp	ALT_ENTER, 1
		jne	@@no_need_to_wait
		
		mov	cx, 24	; If user presses ALT-ENTER we will wait
	@@L3:			; for about 1.5 seconds before proceding.
		push	cx
		mov	ah, 0
		int	1Ah		; Read System Timer
		mov	bx, dx

	@@WT1:	int	1Ah		; Wait one timer tick
		cmp	bx, dx
		je 	@@WT1
		pop	cx
		loop	@@L3

@@no_need_to_wait:

		mov	di, ACT_MBR_REC
		mov	dl, [di]	; Boot sector expects Drive# in DL
	;	jmp	0000h:7C00h	; Transfer control to loaded BootSector
		DB	0EAh
		DW	7C00h,0000h
_ADV_MANAGER	ENDP
		;
		;
		;
INIT_SCREEN	PROC	NEAR

		test	adv_options, ADV_OPT_CLEAR_SCR
		jz	@@skip1
		mov	ah, White+BakBlack
		mov	bl, 1
		mov	bh, 1
		mov	dl, 80
		mov	dh, 25
		call	_clear_window
		mov	bl, 1
		mov	bh, 1
		call	_move_cursor
@@skip1:
		call	_save_cursor
		call	_hide_cursor

		mov	bl, X
		mov	bh, Y
		mov	dl, W
		mov	dh, H
		lea	si, SAV_BUFFER
		call	_save_window

		mov	ah, BORDER_COLOR
		lea	si, Border
		call	_border_window
		
		mov	ah, TITLE_COLOR
		add	bx, 0109h
		lea	si, adv_title
		call	_write_string
		
		mov	ah, KEYS_TXT_COLOR
		mov	bl, KEYS_X
		mov	bh, KEYS_Y
		lea	si, BottomKeysText2
		call	_write_string
		
		mov	ah, KEYS_KEY_COLOR
		add	bl, 6
		lea	si, BottomKeysEnt
		call	_write_string

		
		ret
INIT_SCREEN	ENDP
		;
		;
		;
DONE_SCREEN	PROC	NEAR
		mov	bl, X
		mov	bh, Y
		mov	dl, W
		mov	dh, H
		lea	si, SAV_BUFFER
		call	_load_window
		
		call	_restore_cursor
		ret
DONE_SCREEN	ENDP
		;
		;
		;
PREP_MENU_LIST	PROC	NEAR
		test	adv_options, ADV_OPT_DEF_MENU
		jz	@@no_def_menu
		mov	al, adv_def_menu
		mov	adv_act_menu, al
	@@no_def_menu:
		mov	ACT_MENU, 0
		mov	NUM_MENUS, 0
		mov	cx, 0
		lea	si, menu
		mov	di, 0
	@@next:
		cmp	[si].m_type, M_BOOT_EMPTY
		je	@@cont

		mov	MENU_PTR[di], si
		mov	al, [si].m_tag
		call	PART_NUM_BY_TAG
		jnc	@@part_ok
		cmp	[si].m_type, M_BOOT_PART
		je	@@cont
		mov	ax, 0
	@@part_ok:
		mov	PART_PTR[di], ax

		cmp	cl, adv_act_menu
		jne	@@skip
		mov	ax, NUM_MENUS
		mov	ACT_MENU, ax
	@@skip:
		add	di, 2
		inc	NUM_MENUS
	@@cont:
		add	si, SIZE adv_menu_rec
		inc	cx
		cmp	cx, MAX_MENU_ROWS
		jne	@@next
		ret
PREP_MENU_LIST	ENDP
		;
		;
		;
PART_NUM_BY_TAG	PROC	NEAR
		;
		;  Input:  AL - Tag
		;  Output: AX - Pointer to partition
		;
		;  CF - Set if part not found, AX=0
		;
		push	bx
		push	cx
		cmp	al, 0
		je	@@fail
		xor	cx, cx
		lea	bx, part
	@@next:
		cmp	[bx].p_tag, al
		jne	@@cont
		clc
		mov	ax, bx
		jmp	@@end
	@@cont:
		add	bx, SIZE adv_part_rec
		inc	cx
		cmp	cx, MAX_PART_ROWS
		jne	@@next
	@@fail:
		stc
		mov	ax, 0
	@@end:
		pop	cx
		pop	bx
		ret
PART_NUM_BY_TAG	ENDP
		;
		;
		;
MAIN_MENU	PROC	NEAR
		;
		;	Main loop		
		;
		cmp	IMPORTED_FLAG, 10h
		jb	@@no_import
		lea	si, MesgImported
		call	SHOW_ERROR
@@no_import:
		mov	di, 0
		mov	FILL_KB_BUFFER, 1
@@while1:
		mov	ax, 0
		jmp	@@cond1
	@@next1:
		call	SPRINTF_MENU
		push	ax
		mov	bl, (X+3)
		mov	bh, (Y+3)
		add	bh, al
		cmp	ax, ACT_MENU
		mov	ah, MENU_COLOR
		jne	@@norm1
		mov	ah, ACTIVE_COLOR
	@@norm1:
		lea	si, TMP
		call	_write_string
		pop	ax
		inc	ax
	@@cond1:
		cmp	ax, NUM_MENUS
		jne	@@next1


		mov	ALT_ENTER, 0

		cmp	di, 0
		jne	@@wait_key
					; First time here
		cmp	adv_timeout, 0
		je	@@wait_key

		xor	ah, ah
		mov	al, adv_timeout
		inc	ax
		shr	ax, 1
		mov	TICKS_PER_DOT, ax
		call	DOT_BAR
		jnc	@@no_keys	; no keys was pressed - time run out
		mov	ah, 10h
		int	16h
		cmp	al, ' '
		jne	@@cmp_keys
		jmp	@@wait_key
	@@no_keys:
		jmp	@@boot
	@@wait_key:
		mov	ah, 10h
		int	16h
	@@cmp_keys:
		cmp	ax, 48E0h
		je	@@up
		cmp	ax, 4800h
		je	@@up
		cmp	ax, 50E0h
		je	@@down
		cmp	ax, 5000h
		je	@@down
		cmp	ax, 47E0h
		je	@@home
		cmp	ax, 4700h
		je	@@home
		cmp	ax, 4FE0h
		je	@@end
		cmp	ax, 4F00h
		je	@@end
		cmp	ax, 3920h	; Space
		je	@@space
		cmp	ax, 1C0Dh	; Enter
		je	@@boot2short
		cmp	ax, 0E00Dh	; Enter
		je	@@boot2short
		cmp	ax, 1C00h	; Alt-Enter
		je	@@alt_boot2short
		cmp	ax, 0A600h	; Alt-Enter
		je	@@alt_boot2short
		cmp	ax, 011Bh	; ESC
		je	@@boot_esc2short
		cmp	al, 'A'
		je	@@boot_a_short
		cmp	al, 'a'
		je	@@boot_a_short
		cmp	al, 9	; Tab
		je	@@boot_d_short
		cmp	al, 'H'
		je	@@hide_all
		cmp	al, 'h'
		je	@@hide_all
		sub	al, '1'
		xor	ah, ah

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -