FreeDOS/kernel/kernel.asm
C. Masloch d91c14723a kernel: optimise A20 check and enable/disable calls
Some assembly tricks:

* SMC instead of checking the XMS driver address
in the DOS DS stub,

* SMC so that the address goes right into a
`call far immediate` instruction,

* use `repe cmpsw` to compare multiple words (saves
space over the individual word compares),

* near calls to far functions use push cs to build
a far-call stack frame,

* segments 0 and FFFFh generated by segment arithmetic
instead of loading from memory,

* common case (A20 already enabled) made to be the case
where the conditional branch just falls through, which
may be slightly better.
2022-05-29 19:24:00 -04:00

1270 lines
44 KiB
NASM

;
; File:
; kernel.asm
; Description:
; kernel start-up code
;
; Copyright (c) 1995, 1996
; Pasquale J. Villani
; All Rights Reserved
;
; This file is part of DOS-C.
;
; DOS-C is free software; you can redistribute it and/or
; modify it under the terms of the GNU General Public License
; as published by the Free Software Foundation; either version
; 2, or (at your option) any later version.
;
; DOS-C is distributed in the hope that it will be useful, but
; WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
; the GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public
; License along with DOS-C; see the file COPYING. If not,
; write to the Free Software Foundation, 675 Mass Ave,
; Cambridge, MA 02139, USA.
;
; $Id: kernel.asm 1705 2012-02-07 08:10:33Z perditionc $
;
%include "segs.inc"
%include "stacks.inc"
%include "ludivmul.inc"
segment PSP
extern _ReqPktPtr
STACK_SIZE equ 384/2 ; stack allocated in words
;************************************************************
; KERNEL BEGINS HERE, i.e. this is byte 0 of KERNEL.SYS
;************************************************************
%ifidn __OUTPUT_FORMAT__, obj
..start:
%endif
entry:
jmp short realentry
;************************************************************
; KERNEL CONFIGURATION AREA
; this is copied up on the very beginning
; it's a good idea to keep this in sync with KConfig.h
;************************************************************
global _LowKernelConfig
_LowKernelConfig:
config_signature:
db 'CONFIG' ; constant
dw configend-configstart; size of config area
; to be checked !!!
configstart:
DLASortByDriveNo db 0 ; sort disks by drive order
InitDiskShowDriveAssignment db 1 ;
SkipConfigSeconds db 2 ;
ForceLBA db 0 ;
GlobalEnableLBAsupport db 1 ;
BootHarddiskSeconds db 0 ;
; The following VERSION resource must be keep in sync with VERSION.H
Version_OemID db 0xFD ; OEM_ID
Version_Major db 2
Version_Revision dw 41 ; REVISION_SEQ
Version_Release dw 1 ; 0=release build, >0=svn#
CheckDebugger: db 0 ; 0 = no check, 1 = check, 2 = assume present
configend:
kernel_config_size: equ configend - config_signature
; must be below-or-equal the size of struct _KernelConfig
; in the file kconfig.h !
;************************************************************
; KERNEL CONFIGURATION AREA END
;************************************************************
;************************************************************
; KERNEL real entry (at ~60:20)
;
; moves the INIT part of kernel.sys to high memory (~9000:0)
; then jumps there
; to aid debugging, some '123' messages are output
; this area is discardable and used as temporary PSP for the
; init sequence
;************************************************************
cpu 8086 ; (keep initial entry compatible)
global realentry
realentry: ; execution continues here
clc ; this is patched to stc by exeflat
adc byte [cs:use_upx_config], 0
; ! ZF used later in initialise_command_line_buffer
push ax
push bx
pushf
mov ax, 0e31h ; '1' Tracecode - kernel entered
mov bx, 00f0h
int 010h
popf
pop bx
pop ax
jmp IGROUP:kernel_start
use_upx_config: db 0
beyond_entry: times 256-(beyond_entry-entry) db 0
; scratch area for data (DOS_PSP)
segment INIT_TEXT
extern _FreeDOSmain
extern _query_cpu
;
; kernel start-up
;
kernel_start:
push bx
pushf
mov ax, 0e32h ; '2' Tracecode - kernel entered
mov bx, 00f0h
int 010h
popf
pop bx
extern _kernel_command_line
; preserve unit in bl
initialise_command_line_buffer:
mov dx, I_GROUP
mov es, dx
mov ax, ss
mov ds, ax
mov ax, sp ; ds:ax = ss:sp
mov si, bp ; si = bp
jz .notupx ; ! ZF still left by adc
xor ax, ax
mov ds, ax ; :5E0h -> UPX help data
lds si, [5E0h + 1Ch] ; -> original ss:sp - 2
lea ax, [si + 2] ; ax = original sp
mov si, word [si] ; si = original bp
.notupx:
; Note that the kernel command line buffer in
; the init data segment is pre-initialised to
; hold 0x00 0xFF in the first two bytes. This
; is used to indicate no command line present,
; as opposed to an empty command line which
; will hold 0x00 0x00.
; If any of the branches to .none are taken then
; the buffer is not modified so it retains the
; 0x00 0xFF contents.
cmp si, 114h ; buffer fits below ss:bp ?
jb .none ; no -->
cmp word [si - 14h], "CL" ; signature passed to us ?
jne .none ; no -->
lea si, [si - 114h] ; -> command line buffer
cmp ax, si ; stack top starts below-or-equal buffer ?
ja .none ; no -->
mov di, _kernel_command_line ; our buffer
mov cx, 255
xor ax, ax
push di
rep movsb ; copy up to 255 bytes
stosb ; truncate
pop di
mov ch, 1 ; cx = 256
repne scasb ; scan for terminator
rep stosb ; clear remainder of buffer
; (make sure we do not have 0x00 0xFF
; even if the command line given is
; actually the empty string)
.none:
cli
mov ss, dx
mov sp, init_tos
int 12h ; move init text+data to higher memory
mov cl,6
shl ax,cl ; convert kb to para
mov dx,15 + INITSIZE
mov cl,4
shr dx,cl
sub ax,dx
mov es,ax
mov dx,INITTEXTSIZE ; para aligned
shr dx,cl
add ax,dx
mov ss,ax ; set SS to init data segment
sti ; now enable them
mov ax,cs
mov dx,__HMATextEnd ; para aligned
shr dx,cl
%ifdef WATCOM
add ax,dx
%endif
mov ds,ax
mov si,-2 + INITSIZE; word aligned
lea cx,[si+2]
mov di,si
shr cx,1
std ; if there's overlap only std is safe
rep movsw
; move HMA_TEXT to higher memory
sub ax,dx
mov ds,ax ; ds = HMA_TEXT
mov ax,es
sub ax,dx
mov es,ax ; es = new HMA_TEXT
mov si,-2 + __HMATextEnd
lea cx,[si+2]
mov di,si
shr cx,1
rep movsw
cld
%ifndef WATCOM ; for WATCOM: CS equal for HMA and INIT
add ax,dx
mov es,ax ; otherwise CS -> init_text
%endif
push es
mov ax,cont
push ax
retf
cont: ; Now set up call frame
mov ds,[cs:_INIT_DGROUP]
mov bp,sp ; and set up stack frame for c
push bx
pushf
mov ax, 0e33h ; '3' Tracecode - kernel entered
mov bx, 00f0h
int 010h
popf
pop bx
mov byte [_BootDrive],bl ; tell where we came from
;!! int 11h
;!! mov cl,6
;!! shr al,cl
;!! inc al
;!! mov byte [_NumFloppies],al ; and how many
call _query_cpu
%if XCPU != 86
%if XCPU < 186 || (XCPU % 100) != 86 || (XCPU / 100) > 9
%fatal Unknown CPU level defined
%endif
cmp al, (XCPU / 100)
jb cpu_abort ; if CPU not supported -->
cpu XCPU
%endif
mov [_CPULevel], al
initialise_kernel_config:
extern _InitKernelConfig
push ds
pop es ; => DOS data segment (for _BootDrive)
mov ax, ss ; => init data segment
mov si, 60h
mov ds, si ; => entry section
mov si, _LowKernelConfig ; -> our own CONFIG block
; This block is part of what got decompressed if
; the kernel is UPX-compressed. And if UPX was
; used in .SYS mode then the first several words
; are overwritten with pseudo device header fields.
cmp byte [use_upx_config], 0 ; from UPX ?
je .notupx ; no, use own CONFIG block -->
mov si, 5Eh
mov ds, si
mov si, 2 ; -> CONFIG block of compressed entry
mov bl, [0] ; 05E0h has the boot load unit
mov byte [es:_BootDrive], bl ; overwrite the value in DOS data segment
.notupx:
mov es, ax ; => init data segment
mov di, _InitKernelConfig ; -> init's CONFIG block buffer
mov cx, kernel_config_size / 2 ; size that we support
rep movsw ; copy it over
%if kernel_config_size & 1
movsb ; allow odd size
%endif
mov ds, ax ; => init data segment
check_debugger_present:
extern _debugger_present
mov al, 1 ; assume debugger present
cmp byte [di - kernel_config_size + (CheckDebugger - config_signature)], 1
ja .skip_ints_00_06 ; 2 means assume present
jb .absent ; 0 means assume absent
clc ; 1 means check
int3 ; break to debugger
jc .skip_ints_00_06
; The debugger should set CY here to indicate its
; presence. The flag set is checked later to skip
; overwriting the interrupt vectors 00h, 01h, 03h,
; and 06h. This logic is taken from lDOS init.
.absent:
xor ax, ax ; no debugger present
.skip_ints_00_06:
mov byte [_debugger_present], al
jmp _FreeDOSmain
%if XCPU != 86
cpu 8086
cpu_abort:
mov ah, 0Fh
int 10h ; get video mode, bh = active page
call .first ; print string that follows (address pushed by call)
%define LOADNAME "FreeDOS"
db 13,10 ; (to emit a blank line after the tracecodes)
db 13,10
db LOADNAME, " load error: An 80", '0'+(XCPU / 100)
db "86 processor or higher is required by this build.",13,10
db "To use ", LOADNAME, " on this processor please"
db " obtain a compatible build.",13,10
db 13,10
db "Press any key to reboot.",13,10
db 0
.display:
mov ah, 0Eh
mov bl, 07h ; page in bh, bl = colour for some modes
int 10h ; write character (may change bp!)
db 0A8h ; [test al,imm8] skip "pop si" [=imm8] after the first iteration
.first:
pop si ; (first iteration only) get message address from stack
cs lodsb ; get character
test al, al ; zero ?
jnz .display ; no, display and get next character -->
xor ax, ax
xor dx, dx
int 13h ; reset floppy disks
xor ax, ax
mov dl, 80h
int 13h ; reset hard disks
; this "test ax, imm16" opcode is used to
db 0A9h ; skip "sti" \ "hlt" [=imm16] during first iteration
.wait:
sti
hlt ; idle while waiting for keystroke
mov ah, 01h
int 16h ; get keystroke
jz .wait ; none available, loop -->
mov ah, 00h
int 16h ; remove keystroke from buffer
int 19h ; reboot
jmp short $ ; (in case it returns, which it shouldn't)
cpu XCPU
%endif ; XCPU != 86
segment INIT_TEXT_END
;************************************************************
; KERNEL CODE AREA END
; the NUL device
;************************************************************
segment CONST
;
; NUL device strategy
;
global _nul_strtgy
extern GenStrategy
_nul_strtgy:
jmp LGROUP:GenStrategy
;
; NUL device interrupt
;
global _nul_intr
_nul_intr:
push es
push bx
mov bx,LGROUP
mov es,bx
les bx,[es:_ReqPktPtr] ;es:bx--> rqheadr
cmp byte [es:bx+2],4 ;if read, set 0 read
jne no_nul_read
mov word [es:bx+12h],0
no_nul_read:
or word [es:bx+3],100h ;set "done" flag
pop bx
pop es
retf
segment _LOWTEXT
; low interrupt vectors 10h,13h,15h,19h,1Bh
; these need to be at 0070:0100 (see RBIL memory.lst)
global _intvec_table
_intvec_table: db 10h
dd 0
; used by int13 handler and get/set via int 2f/13h
global _BIOSInt13 ; BIOS provided disk handler
global _UserInt13 ; actual disk handler used by kernel
db 13h
_BIOSInt13: dd 0
db 15h
dd 0
; used for cleanup on reboot
global _BIOSInt19
db 19h
_BIOSInt19: dd 0
db 1Bh
dd 0
; default to using BIOS provided disk handler
db 13h
_UserInt13: dd 0
; floppy parameter table
global _int1e_table
_int1e_table: times 0eh db 0
;************************************************************
; KERNEL FIXED DATA AREA
;************************************************************
segment _FIXED_DATA
; Because of the following bytes of data, THIS MODULE MUST BE THE FIRST
; IN THE LINK SEQUENCE. THE BYTE AT DS:0004 determines the SDA format in
; use. A 0 indicates MS-DOS 3.X style, a 1 indicates MS-DOS 4.0-6.X style.
global DATASTART
DATASTART:
global _DATASTART
_DATASTART:
dos_data db 0
dw kernel_start
db 0 ; padding
dw 1 ; Hardcoded MS-DOS 4.0+ style
times (0eh - ($ - DATASTART)) db 0
global _NetBios
_NetBios dw 0 ; NetBios Number
times (26h - 0ch - ($ - DATASTART)) db 0
; Globally referenced variables - WARNING: DO NOT CHANGE ORDER
; BECAUSE THEY ARE DOCUMENTED AS UNDOCUMENTED (?) AND HAVE
; MANY MULTIPLEX PROGRAMS AND TSRs ACCESSING THEM
global _NetRetry
_NetRetry dw 3 ;-000c network retry count
global _NetDelay
_NetDelay dw 1 ;-000a network delay count
global _DskBuffer
_DskBuffer dd -1 ;-0008 current dos disk buffer
global _inputptr
_inputptr dw 0 ;-0004 Unread con input
global _first_mcb
_first_mcb dw 0 ;-0002 Start of user memory
global _DPBp
global MARK0026H
; A reference seems to indicate that this should start at offset 26h.
MARK0026H equ $
_DPBp dd 0 ; 0000 First drive Parameter Block
global _sfthead
_sfthead dd 0 ; 0004 System File Table head
global _clock
_clock dd 0 ; 0008 CLOCK$ device
global _syscon
_syscon dw _con_dev,LGROUP ; 000c console device
global _maxsecsize
_maxsecsize dw 512 ; 0010 maximum bytes/sector of any block device
dd 0 ; 0012 pointer to buffers info structure
global _CDSp
_CDSp dd 0 ; 0016 Current Directory Structure
global _FCBp
_FCBp dd 0 ; 001a FCB table pointer
global _nprotfcb
_nprotfcb dw 0 ; 001e number of protected fcbs
global _nblkdev
_nblkdev db 0 ; 0020 number of block devices
global _lastdrive
_lastdrive db 0 ; 0021 value of last drive
global _nul_dev
_nul_dev: ; 0022 device chain root
extern _con_dev
dw _con_dev, LGROUP
; next is con_dev at init time.
dw 8004h ; attributes = char device, NUL bit set
dw _nul_strtgy
dw _nul_intr
db 'NUL '
global _njoined
_njoined db 0 ; 0034 number of joined devices
dw 0 ; 0035 DOS 4 pointer to special names (always zero in DOS 5)
global _setverPtr
_setverPtr dw 0,0 ; 0037 setver list
dw 0 ; 003B cs offset for fix a20
dw 0 ; 003D psp of last umb exec
global _LoL_nbuffers
_LoL_nbuffers dw 1 ; 003F number of buffers
dw 1 ; 0041 size of pre-read buffer
global _BootDrive
_BootDrive db 1 ; 0043 drive we booted from
global _CPULevel
_CPULevel db 0 ; 0044 cpu type (MSDOS >0 indicates dword moves ok, ie 386+)
; unless compatibility issues arise FD uses
; 0=808x, 1=18x, 2=286, 3=386+
; see cpu.asm, use >= as may add checks for 486 ...
dw 0 ; 0045 Extended memory in KBytes
buf_info:
global _firstbuf
_firstbuf dd 0 ; 0047 disk buffer chain
dw 0 ; 004B Number of dirty buffers
dd 0 ; 004D pre-read buffer
dw 0 ; 0051 number of look-ahead buffers
global _bufloc
_bufloc db 0 ; 0053 00=conv 01=HMA
global _deblock_buf
_deblock_buf dd 0 ; 0054 deblock buffer
times 3 db 0 ; 0058 unknown
dw 0 ; 005B unknown
db 0, 0FFh, 0 ; 005D unknown
global _VgaSet
_VgaSet db 0 ; 0060 unknown
dw 0 ; 0061 unknown
global _uppermem_link
_uppermem_link db 0 ; 0063 upper memory link flag
_min_pars dw 0 ; 0064 minimum paragraphs of memory
; required by program being EXECed
global _uppermem_root
_uppermem_root dw 0ffffh ; 0066 dmd_upper_root (usually 9fff)
_last_para dw 0 ; 0068 para of last mem search
SysVarEnd:
;; FreeDOS specific entries
;; all variables below this point are subject to relocation.
;; programs should not rely on any values below this point!!!
global _os_setver_minor
_os_setver_minor db 0
global _os_setver_major
_os_setver_major db 5
global _os_minor
_os_minor db 0
global _os_major
_os_major db 5
_rev_number db 0
global _version_flags
_version_flags db 0
global os_release
extern _os_release
os_release dw _os_release
%IFDEF WIN31SUPPORT
global _winStartupInfo, _winInstanced
_winInstanced dw 0 ; set to 1 on WinInit broadcast, 0 on WinExit broadcast
_winStartupInfo:
dw 0 ; structure version (same as windows version)
dd 0 ; next startup info structure, 0:0h marks end
dd 0 ; far pointer to name virtual device file or 0:0h
dd 0 ; far pointer, reference data for virtual device driver
dw instance_table,seg instance_table ; array of instance data
instance_table: ; should include stacks, Win may auto determine SDA region
; we simply include whole DOS data segment
dw seg _DATASTART, 0 ; [SEG:OFF] address of region's base
dw markEndInstanceData wrt seg _DATASTART ; size in bytes
dd 0 ; 0 marks end of table
dw 0 ; and 0 length for end of instance_table entry
global _winPatchTable
_winPatchTable: ; returns offsets to various internal variables
dw 0x0006 ; DOS version, major# in low byte, eg. 6.00
dw save_DS ; where DS stored during int21h dispatch
dw save_BX ; where BX stored during int21h dispatch
dw _InDOS ; offset of InDOS flag
dw _MachineId ; offset to variable containing MachineID
dw _CritPatch ; offset of to array of offsets to patch
; NOTE: this points to a null terminated
; array of offsets of critical section bytes
; to patch, for now we can just point this
; to an empty table
; ie we just point to a 0 word to mark end
dw _uppermem_root ; seg of last arena header in conv memory
; this matches MS DOS's location, but
; do we have the same meaning?
%ENDIF ; WIN31SUPPORT
;; The first 5 sft entries appear to have to be at DS:00cc
times (0cch - ($ - DATASTART)) db 0
global _firstsftt
_firstsftt:
dd -1 ; link to next
dw 5 ; count
times 5*59 db 0 ; reserve space for the 5 sft entries
db 0 ; pad byte so next value on even boundary
; Some references seem to indicate that this data should start at 01fbh in
; order to maintain 100% MS-DOS compatibility.
times (01fbh - ($ - DATASTART)) db 0
global MARK01FBH
MARK01FBH equ $
global _local_buffer ; local_buffer is 256 bytes long
; so it overflows into kb_buf!!
; only when kb_buf is used, local_buffer is limited to 128 bytes.
_local_buffer: times 128 db 0
global _kb_buf
_kb_buf db 128,0 ; initialise buffer to empty
times 128+1 db 0 ; room for 128 byte readline + LF
;
; Variables that follow are documented as part of the DOS 4.0-6.X swappable
; data area in Ralf Browns Interrupt List #56
;
; this byte is used for ^P support
global _PrinterEcho
_PrinterEcho db 0 ;-34 - 0 = no printer echo, ~0 echo
global _verify_ena
_verify_ena db 0 ; ~0, write with verify
; this byte is used for TABs (shared by all char device writes??)
global _scr_pos
_scr_pos db 0 ; Current Cursor Column
global _switchar
_switchar db '/' ;-31 - switch char
global _mem_access_mode
_mem_access_mode db 0 ;-30 - memory allocation strategy
global sharing_flag
sharing_flag db 0 ; 00 = sharing module not loaded
; 01 = sharing module loaded, but
; open/close for block devices
; disabled
; FF = sharing module loaded,
; open/close for block devices
; enabled (not implemented)
global _net_set_count
_net_set_count db 1 ;-28 - count the name below was set
global _net_name
_net_name db ' ' ;-27 - 15 Character Network Name
db 00 ; Terminating 0 byte
;
; Variables contained the the "STATE_DATA" segment contain
; information about the STATE of the current DOS Process. These
; variables must be preserved regardless of the state of the INDOS
; flag.
;
; All variables that appear in "STATE_DATA" **MUST** be declared
; in this file as the offsets from the INTERNAL_DATA variable are
; critical to the DOS applications that modify this data area.
;
;
global _ErrorMode, _InDOS
global _CritErrLocus, _CritErrCode
global _CritErrAction, _CritErrClass
global _CritErrDev, _CritErrDrive
global _dta
global _cu_psp, _default_drive
global _break_ena
global _return_code
global _internal_data
; ensure offset of critical patch table remains fixed, some programs hard code offset
times (0315h - ($ - DATASTART)) db 0
global _CritPatch
_CritPatch dw 0 ;-11 zero list of patched critical
dw 0 ; section variables
dw 0 ; DOS puts 0d0ch here but some
dw 0 ; progs really write to that addr.
dw 0 ;-03 - critical patch list terminator
db 90h ;-01 - unused, NOP pad byte
_internal_data: ; <-- Address returned by INT21/5D06
_ErrorMode db 0 ; 00 - Critical Error Flag
_InDOS db 0 ; 01 - Indos Flag
_CritErrDrive db 0 ; 02 - Drive on write protect error
_CritErrLocus db 0 ; 03 - Error Locus
_CritErrCode dw 0 ; 04 - DOS format error Code
_CritErrAction db 0 ; 06 - Error Action Code
_CritErrClass db 0 ; 07 - Error Class
_CritErrDev dd 0 ; 08 - Failing Device Address
_dta dd 0 ; 0C - current DTA
_cu_psp dw 0 ; 10 - Current PSP
break_sp dw 0 ; 12 - used in int 23
_return_code dw 0 ; 14 - return code from process
_default_drive db 0 ; 16 - Current Drive
_break_ena db 1 ; 17 - Break Flag (default TRUE)
db 0 ; 18 - flag, code page switching
db 0 ; 19 - flag, copy of 18 on int 24h abort
global _swap_always, _swap_indos
_swap_always:
global _Int21AX
_Int21AX dw 0 ; 1A - AX from last Int 21
global owning_psp, _MachineId
owning_psp dw 0 ; 1C - owning psp
_MachineId dw 0 ; 1E - remote machine ID
dw 0 ; 20 - First usable mcb
dw 0 ; 22 - Best usable mcb
dw 0 ; 24 - Last usable mcb
dw 0 ; 26 - memory size in paragraphs
dw 0 ; 28 - unknown
db 0 ; 2A - unknown
db 0 ; 2B - unknown
db 0 ; 2C - unknown
global _break_flg
_break_flg db 0 ; 2D - Program aborted by ^C
db 0 ; 2E - unknown
db 0 ; 2F - not referenced
global _DayOfMonth
_DayOfMonth db 1 ; 30 - day of month
global _Month
_Month db 1 ; 31 - month
global _YearsSince1980
_YearsSince1980 dw 0 ; 32 - year since 1980
daysSince1980 dw 0FFFFh ; 34 - number of days since epoch
; force rebuild on first clock read
global _DayOfWeek
_DayOfWeek db 2 ; 36 - day of week
_console_swap db 0 ; 37 console swapped during read from dev
global _dosidle_flag
_dosidle_flag db 1 ; 38 - safe to call int28 if nonzero
_abort_progress db 0 ; 39 - abort in progress
global _CharReqHdr
_CharReqHdr:
global _ClkReqHdr
_ClkReqHdr times 30 db 0 ; 3A - Device driver request header
dd 0 ; 58 - pointer to driver entry
global _MediaReqHdr
_MediaReqHdr times 22 db 0 ; 5C - Device driver request header
global _IoReqHdr
_IoReqHdr times 30 db 0 ; 72 - Device driver request header
times 6 db 0 ; 90 - unknown
global _ClkRecord
_ClkRecord times 6 db 0 ; 96 - CLOCK$ transfer record
dw 0 ; 9C - unknown
global __PriPathBuffer
__PriPathBuffer times 80h db 0 ; 9E - buffer for file name
global __SecPathBuffer
__SecPathBuffer times 80h db 0 ;11E - buffer for file name
global _sda_tmp_dm
_sda_tmp_dm times 21 db 0 ;19E - 21 byte srch state
global _SearchDir
_SearchDir times 32 db 0 ;1B3 - 32 byte dir entry
global _TempCDS
_TempCDS times 88 db 0 ;1D3 - TemporaryCDS buffer
global _DirEntBuffer
_DirEntBuffer times 32 db 0 ;22B - space enough for 1 dir entry
global _wAttr
_wAttr dw 0 ;24B - extended FCB file attribute
global _SAttr
_SAttr db 0 ;24D - Attribute Mask for Dir Search
global _OpenMode
_OpenMode db 0 ;24E - File Open Attribute
times 3 db 0
global _Server_Call
_Server_Call db 0 ;252 - Server call Func 5D sub 0
db 0
; Pad to 05CCh
times (25ch - ($ - _internal_data)) db 0
global _tsr ; used by break and critical error
_tsr db 0 ;25C - handlers during termination
db 0 ;25D - padding
global term_psp
term_psp dw 0 ;25E - 0??
global int24_esbp
int24_esbp times 2 dw 0 ;260 - pointer to criticalerr DPB
global _user_r, int21regs_off, int21regs_seg
_user_r:
int21regs_off dw 0 ;264 - pointer to int21h stack frame
int21regs_seg dw 0
global critical_sp
critical_sp dw 0 ;268 - critical error internal stack
global current_ddsc
current_ddsc times 2 dw 0
; Pad to 059ah
times (27ah - ($ - _internal_data)) db 0
global current_device
current_device times 2 dw 0 ;27A - 0??
global _lpCurSft
_lpCurSft times 2 dw 0 ;27e - Current SFT
global _current_ldt
_current_ldt times 2 dw 0 ;282 - Current CDS
global _sda_lpFcb
_sda_lpFcb times 2 dw 0 ;286 - pointer to callers FCB
global _current_sft_idx
_current_sft_idx dw 0 ;28A - SFT index for next open
; used by MS NET
; Pad to 05b2h
times (292h - ($ - _internal_data)) db 0
dw __PriPathBuffer ; 292 - "sda_WFP_START" offset in DOS DS of first filename argument
dw __SecPathBuffer ; 294 - "sda_REN_WFP" offset in DOS DS of second filename argument
; Pad to 05ceh
times (2aeh - ($ - _internal_data)) db 0
global _current_filepos
_current_filepos times 2 dw 0 ;2AE - current offset in file
; Pad to 05eah
times (2cah - ($ - _internal_data)) db 0
;global _save_BX
;global _save_DS
save_BX dw 0 ;2CA - unused by FreeDOS, for Win3.x
save_DS dw 0 ; compatibility, match MS's positions
dw 0
global _prev_user_r
global prev_int21regs_off
global prev_int21regs_seg
_prev_user_r:
prev_int21regs_off dw 0 ;2D0 - pointer to prev int 21 frame
prev_int21regs_seg dw 0
; Pad to 05fdh
times (2ddh - ($ - _internal_data)) db 0
global _ext_open_action
global _ext_open_attrib
global _ext_open_mode
_ext_open_action dw 0 ;2DD - extended open action
_ext_open_attrib dw 0 ;2DF - extended open attrib
_ext_open_mode dw 0 ;2E1 - extended open mode
; Pad to 0620h
times (300h - ($ - _internal_data)) db 0
global apistk_bottom
apistk_bottom:
; use bottom of error stack as scratch buffer
; - only used during int 21 call
global _sda_tmp_dm_ren
_sda_tmp_dm_ren:times 21 db 0x90 ;300 - 21 byte srch state for rename
global _SearchDir_ren
_SearchDir_ren: times 32 db 0x90 ;315 - 32 byte dir entry for rename
; stacks are made to initialize to no-ops so that high-water
; testing can be performed
times STACK_SIZE*2-($-apistk_bottom) db 0x90
;300 - Error Processing Stack
global _error_tos
_error_tos:
times STACK_SIZE dw 0x9090 ;480 - Disk Function Stack
global _disk_api_tos
_disk_api_tos:
times STACK_SIZE dw 0x9090 ;600 - Char Function Stack
global _char_api_tos
_char_api_tos:
apistk_top:
db 0 ; 780 ???
_VolChange db 0 ;781 - volume change
_VirtOpen db 0 ;782 - virtual open flag
; controlled variables end at offset 78Ch so pad to end
times (78ch - ($ - _internal_data)) db 0
;
; end of controlled variables
;
segment _BSS
;!! global _NumFloppies
;!!_NumFloppies resw 1
;!!intr_dos_stk resw 1
;!!intr_dos_seg resw 1
; mark front and end of bss area to clear
segment IB_B
global __ib_start
__ib_start:
segment IB_E
global __ib_end
__ib_end:
;; do not clear the other init BSS variables + STACK: too late.
; kernel startup stack
global init_tos
resw 512
init_tos:
; the last paragraph of conventional memory might become an MCB
resb 16
global __init_end
__init_end:
init_end:
segment _DATA
; blockdev private stack
global blk_stk_top
times 256 dw 0
blk_stk_top:
; clockdev private stack
global clk_stk_top
times 128 dw 0
clk_stk_top:
; int2fh private stack
global int2f_stk_top
times 128 dw 0
int2f_stk_top:
; Dynamic data:
; member of the DOS DATA GROUP
; and marks definitive end of all used data in kernel data segment
;
segment _DATAEND
_swap_indos:
; we don't know precisely what needs to be swapped before this, so set it here.
; this is just after FIXED_DATA+BSS+DATA and before (D)CONST+BSS
; probably, the clock and block stacks and disktransferbuffer should go past
; _swap_indos but only if int2a ah=80/81 (critical section start/end)
; are called upon entry and exit of the device drivers
times 96 dw 0x9090 ; Process 0 Stack
global _p_0_tos
_p_0_tos:
segment DYN_DATA
global _Dyn
_Dyn:
DynAllocated dw 0
markEndInstanceData: ; mark end of DOS data seg we say needs instancing
segment ID_B
global __INIT_DATA_START
__INIT_DATA_START:
segment ID_E
global __INIT_DATA_END
__INIT_DATA_END:
segment INIT_TEXT_START
global __InitTextStart
__InitTextStart: ; and c version
segment INIT_TEXT_END
global __InitTextEnd
__InitTextEnd: ; and c version
;
; start end end of HMA area
segment HMA_TEXT_START
global __HMATextAvailable
__HMATextAvailable:
global __HMATextStart
__HMATextStart:
;
; the HMA area is filled with 1eh+3(=sizeof VDISK) = 33 byte dummy data,
; so nothing will ever be below 0xffff:0031
;
segment HMA_TEXT
begin_hma:
times 10h db 0 ; filler [ffff:0..ffff:10]
times 20h db 0
db 0
; to minimize relocations
global _DGROUP_
_DGROUP_ dw DGROUP
%ifdef WATCOM
; 32 bit multiplication + division
global __U4M
__U4M:
LMULU
global __U4D
__U4D:
LDIVMODU
%endif
%ifdef gcc
%macro ULONG_HELPERS 1
global %1udivsi3
%1udivsi3: call %1ldivmodu
ret 8
global %1umodsi3
%1umodsi3: call %1ldivmodu
mov dx, cx
mov ax, bx
ret 8
%1ldivmodu: LDIVMODU
global %1ashlsi3
%1ashlsi3: LSHLU
global %1lshrsi3
%1lshrsi3: LSHRU
%endmacro
ULONG_HELPERS ___
%endif
times 0xd0 - ($-begin_hma) db 0
; reserve space for far jump to cp/m routine
times 5 db 0
;End of HMA segment
segment HMA_TEXT_END
global __HMATextEnd
__HMATextEnd: ; and c version
; The default stack (_TEXT:0) will overwrite the data area, so I create a dummy
; stack here to ease debugging. -- ror4
segment _STACK class(STACK) nobits stack
segment CONST
; dummy interrupt return handlers
global _int22_handler
global _int28_handler
global _int2a_handler
global _empty_handler
_int22_handler:
_int28_handler:
_int2a_handler:
_empty_handler:
iret
global _initforceEnableA20
initforceEnableA20:
call near forceEnableA20
retf
global __HMARelocationTableStart
__HMARelocationTableStart:
global _int2f_handler
extern reloc_call_int2f_handler
_int2f_handler: jmp 0:reloc_call_int2f_handler
call near forceEnableA20
global _int20_handler
extern reloc_call_int20_handler
_int20_handler: jmp 0:reloc_call_int20_handler
call near forceEnableA20
global _int21_handler
extern reloc_call_int21_handler
_int21_handler: jmp 0:reloc_call_int21_handler
call near forceEnableA20
global _low_int25_handler
extern reloc_call_low_int25_handler
_low_int25_handler: jmp 0:reloc_call_low_int25_handler
call near forceEnableA20
global _low_int26_handler
extern reloc_call_low_int26_handler
_low_int26_handler: jmp 0:reloc_call_low_int26_handler
call near forceEnableA20
global _int27_handler
extern reloc_call_int27_handler
_int27_handler: jmp 0:reloc_call_int27_handler
call near forceEnableA20
global _int0_handler
extern reloc_call_int0_handler
_int0_handler: jmp 0:reloc_call_int0_handler
call near forceEnableA20
global _int6_handler
extern reloc_call_int6_handler
_int6_handler: jmp 0:reloc_call_int6_handler
call near forceEnableA20
global _int19_handler
extern reloc_call_int19_handler
_int19_handler: jmp 0:reloc_call_int19_handler
call near forceEnableA20
global _cpm_entry
extern reloc_call_cpm_entry
_cpm_entry: jmp 0:reloc_call_cpm_entry
call near forceEnableA20
global _reloc_call_blk_driver
extern _blk_driver
_reloc_call_blk_driver:
jmp 0:_blk_driver
call near forceEnableA20
global _reloc_call_clk_driver
extern _clk_driver
_reloc_call_clk_driver:
jmp 0:_clk_driver
call near forceEnableA20
global _CharMapSrvc ; in _DATA (see AARD)
extern _reloc_call_CharMapSrvc
_CharMapSrvc: jmp 0:_reloc_call_CharMapSrvc
call near forceEnableA20
global _init_call_p_0
extern reloc_call_p_0
_init_call_p_0: jmp 0:reloc_call_p_0
call near forceEnableA20
global __HMARelocationTableEnd
__HMARelocationTableEnd:
;
; if we were lucky, we found all entries from the outside to the kernel.
; if not, BUMS
;
;
; this routine makes the HMA area available. PERIOD.
; must conserve ALL registers
; will be only ever called, if HMA (DOS=HIGH) is enabled.
; for obvious reasons it should be located at the relocation table
;
global _ENABLEA20
_ENABLEA20:
mov ah,5
UsingXMSdriver:
global _XMS_Enable_Patch
_XMS_Enable_Patch: ; SMC: patch to nop (90h) to enable use of XMS
retf
push bx
call 0:0 ; (immediate far address patched)
global _XMSDriverAddress
_XMSDriverAddress: equ $ - 4 ; XMS driver, if detected
pop bx
retf
global _DISABLEA20
_DISABLEA20:
mov ah,6
jmp short UsingXMSdriver
global forceEnableA20
forceEnableA20:
push ds
push es
push ax
push si
push di
push cx
pushf
cld
.retry:
xor si, si ; = 0000h
mov ds, si ; => low memory (IVT)
dec si ; = FFFFh
mov es, si ; => HMA at offset 10h
inc si ; back to 0, -> IVT entry 0 and 1
mov di, 10h ; -> HMA, or wrapping around to 0:0
mov cx, 4
repe cmpsw ; compare up to 4 words
je .enable
.success:
popf
pop cx
pop di
pop si
pop ax
pop es
pop ds
retn
.enable:
; ok, we have to enable A20 (at least seems so)
push cs ; make far call stack frame
call _ENABLEA20
jmp short .retry
; global f*cking compatibility issues:
;
; very old brain dead software (PKLITE, copyright 1990)
; forces us to execute with A20 disabled
;
global _ExecUserDisableA20
_ExecUserDisableA20:
push ax
push cs ; make far call stack frame
call _DISABLEA20 ; (no-op if not in HMA, patched otherwise)
pop ax
iret
; Default Int 24h handler -- always returns fail
; so we have not to relocate it (now)
;
FAIL equ 03h
global _int24_handler
_int24_handler: mov al,FAIL
iret
;
; this makes some things easier
;
segment _LOWTEXT
global _TEXT_DGROUP
_TEXT_DGROUP dw DGROUP
segment INIT_TEXT
global _INIT_DGROUP
_INIT_DGROUP dw DGROUP
%ifdef gcc
ULONG_HELPERS _init_
%endif