📄 klib88.s
字号:
! Load and return the word at the far pointer segment:offset.
_mem_rdw:
mov cx,ds ! save ds
pop dx ! return adr
pop ds ! segment
pop bx ! offset
sub sp,#2+2 ! adjust for parameters popped
mov ax,(bx) ! load the word to return
mov ds,cx ! restore ds
jmp (dx) ! return
!*===========================================================================*
!* reset *
!*===========================================================================*
! PUBLIC void reset();
! Reset the system.
! In real mode we simply jump to the reset address.
_reset:
jmpf 0,0xFFFF
!*===========================================================================*
!* mem_vid_copy *
!*===========================================================================*
! PUBLIC void mem_vid_copy(u16 *src, unsigned dst, unsigned count);
!
! Copy count characters from kernel memory to video memory. Src, dst and
! count are character (word) based video offsets and counts. If src is null
! then screen memory is blanked by filling it with blank_color.
MVC_ARGS = 2 + 2 + 2 + 2 ! 2 + 2 + 2
! es di si ip src dst ct
_mem_vid_copy:
push si
push di
push es
mov bx, sp
mov si, MVC_ARGS(bx) ! source
mov di, MVC_ARGS+2(bx) ! destination
mov dx, MVC_ARGS+2+2(bx) ! count
mov es, _vid_seg ! destination is video segment
cld ! make sure direction is up
mvc_loop:
and di, _vid_mask ! wrap address
mov cx, dx ! one chunk to copy
mov ax, _vid_size
sub ax, di
cmp cx, ax
jbe 0f
mov cx, ax ! cx = min(cx, vid_size - di)
0: sub dx, cx ! count -= cx
shl di, #1 ! byte address
test si, si ! source == 0 means blank the screen
jz mvc_blank
mvc_copy:
rep ! copy words to video memory
movs
jmp mvc_test
mvc_blank:
mov ax, _blank_color ! ax = blanking character
rep
stos ! copy blanks to video memory
!jmp mvc_test
mvc_test:
shr di, #1 ! word addresses
test dx, dx
jnz mvc_loop
mvc_done:
pop es
pop di
pop si
ret
!*===========================================================================*
!* vid_vid_copy *
!*===========================================================================*
! PUBLIC void vid_vid_copy(unsigned src, unsigned dst, unsigned count);
!
! Copy count characters from video memory to video memory. Handle overlap.
! Used for scrolling, line or character insertion and deletion. Src, dst
! and count are character (word) based video offsets and counts.
VVC_ARGS = 2 + 2 + 2 + 2 ! 2 + 2 + 2
! es di si ip src dst ct
_vid_vid_copy:
push si
push di
push es
mov bx, sp
mov si, VVC_ARGS(bx) ! source
mov di, VVC_ARGS+2(bx) ! destination
mov dx, VVC_ARGS+2+2(bx) ! count
mov es, _vid_seg ! use video segment
cmp si, di ! copy up or down?
jb vvc_down
vvc_up:
cld ! direction is up
vvc_uploop:
and si, _vid_mask ! wrap addresses
and di, _vid_mask
mov cx, dx ! one chunk to copy
mov ax, _vid_size
sub ax, si
cmp cx, ax
jbe 0f
mov cx, ax ! cx = min(cx, vid_size - si)
0: mov ax, _vid_size
sub ax, di
cmp cx, ax
jbe 0f
mov cx, ax ! cx = min(cx, vid_size - di)
0: sub dx, cx ! count -= cx
shl si, #1
shl di, #1 ! byte addresses
rep
eseg movs ! copy video words
shr si, #1
shr di, #1 ! word addresses
test dx, dx
jnz vvc_uploop ! again?
jmp vvc_done
vvc_down:
std ! direction is down
add si, dx ! start copying at the top
dec si
add di, dx
dec di
vvc_downloop:
and si, _vid_mask ! wrap addresses
and di, _vid_mask
mov cx, dx ! one chunk to copy
lea ax, 1(si)
cmp cx, ax
jbe 0f
mov cx, ax ! cx = min(cx, si + 1)
0: lea ax, 1(di)
cmp cx, ax
jbe 0f
mov cx, ax ! cx = min(cx, di + 1)
0: sub dx, cx ! count -= cx
shl si, #1
shl di, #1 ! byte addresses
rep
eseg movs ! copy video words
shr si, #1
shr di, #1 ! word addresses
test dx, dx
jnz vvc_downloop ! again?
cld ! C compiler expect up
!jmp vvc_done
vvc_done:
pop es
pop di
pop si
ret
!*===========================================================================*
!* level0 *
!*===========================================================================*
! PUBLIC void level0(void (*func)(void))
! Not very interesting in real mode, see p_level0.
!
_level0:
mov bx, sp
jmp @2(bx)
!*===========================================================================*
!* klib_init_prot *
!*===========================================================================*
! PUBLIC void klib_init_prot();
! Initialize klib for protected mode by patching some real mode functions
! at their starts to jump to their protected mode equivalents, according to
! the patch table. Saves a lot of tests on the "protected_mode" variable.
! Note that this function must be run in real mode, for it writes the code
! segment. (One otherwise has to set up a descriptor, etc, etc.)
klib_init_prot:
mov si,#patch_table
kip_next:
lods ! original function
mov bx,ax
cseg movb (bx),#JMP_OPCODE ! overwrite start of function by a long jump
lods ! new function - target of jump
sub ax,bx ! relative jump
sub ax,#3 ! adjust by length of jump instruction
cseg mov 1(bx),ax ! set address
cmp si,#end_patch_table ! end of table?
jb kip_next
kip_done:
ret
!*===========================================================================*
!* variants for protected mode *
!*===========================================================================*
! Some routines are different in protected mode.
! The only essential difference is the handling of segment registers.
! One complication is that the method of building segment descriptors is not
! reentrant, so the protected mode versions must not be called by interrupt
! handlers.
!*===========================================================================*
!* p_cp_mess *
!*===========================================================================*
! The real mode version attempts to be efficient by passing raw segments but
! that just gets in the way here.
p_cp_mess:
cld
pop dx
pop bx ! proc
pop cx ! source clicks
pop ax ! source offset
#if CLICK_SHIFT != HCLICK_SHIFT + 4
#error /* the only click size supported is 256, to avoid slow shifts here */
#endif
addb ah,cl ! calculate source offset
adcb ch,#0 ! and put in base of source descriptor
mov _gdt+DS_286_OFFSET+DESC_BASE,ax
movb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE,ch
pop cx ! destination clicks
pop ax ! destination offset
addb ah,cl ! calculate destination offset
adcb ch,#0 ! and put in base of destination descriptor
mov _gdt+ES_286_OFFSET+DESC_BASE,ax
movb _gdt+ES_286_OFFSET+DESC_BASE_MIDDLE,ch
sub sp,#2+2+2+2+2
push ds
push es
mov ax,#DS_286_SELECTOR
mov ds,ax
mov ax,#ES_286_SELECTOR
mov es,ax
eseg mov 0,bx ! proc no. of sender from arg, not msg
mov ax,si
mov bx,di
mov si,#2 ! src offset is now 2 relative to start of seg
mov di,si ! and destination offset
mov cx,#Msize-1 ! word count
rep
movs
mov di,bx
mov si,ax
pop es
pop ds
jmp (dx)
!*===========================================================================*
!* p_portio_setup *
!*===========================================================================*
! The port_read, port_write, etc. functions need a setup routine that uses
! a segment descriptor.
p_portio_setup:
mov ax,4+2(bp) ! source/destination address in dx:ax
mov dx,4+2+2(bp)
mov _gdt+DS_286_OFFSET+DESC_BASE,ax
movb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE,dl
xor bx,bx ! bx = 0 = start of segment
mov ax,#DS_286_SELECTOR ! ax = segment selector
mov cx,4+2+4(bp) ! count in bytes
mov dx,4(bp) ! port to read from
cld ! direction is UP
ret
!*===========================================================================*
!* p_phys_copy *
!*===========================================================================*
p_phys_copy:
cld
pop dx
pop _gdt+DS_286_OFFSET+DESC_BASE
pop ax ! pop source into base of source descriptor
movb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE,al
pop _gdt+ES_286_OFFSET+DESC_BASE
pop ax ! pop destination into base of dst descriptor
movb _gdt+ES_286_OFFSET+DESC_BASE_MIDDLE,al
pop cx ! byte count in bx:cx
pop bx
sub sp,#4+4+4
push di
push si
push es
push ds
sub si,si ! src offset is now 0 relative to start of seg
mov di,si ! and destination offset
jmp ppc_next
! It is too much trouble to align the segment bases, so word alignment is hard.
! Avoiding the book-keeping for alignment may be good anyway.
ppc_large:
push cx
mov cx,#0x8000 ! copy a large chunk of this many words
rep
movs
pop cx
dec bx
pop ds ! update the descriptors
incb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE
incb _gdt+ES_286_OFFSET+DESC_BASE_MIDDLE
push ds
ppc_next:
mov ax,#DS_286_SELECTOR ! (re)load the selectors
mov ds,ax
mov ax,#ES_286_SELECTOR
mov es,ax
test bx,bx
jnz ppc_large
shr cx,#1 ! word count
rep
movs ! move any leftover words
rcl cx,#1 ! restore old bit 0
rep
movb ! move any leftover byte
pop ds
pop es
pop si
pop di
jmp (dx)
!*===========================================================================*
!* p_reset *
!*===========================================================================*
! Reset the system by loading IDT with offset 0 and interrupting.
p_reset:
lidt idt_zero
int 3 ! anything goes, the 286 will not like it
!*===========================================================================*
!* p_level0 *
!*===========================================================================*
! PUBLIC void level0(void (*func)(void))
! Call a function at permission level 0. This allows kernel tasks to do
! things that are only possible at the most privileged CPU level.
!
p_level0:
mov bx, sp
mov ax, 2(bx)
mov _level0_func, ax
int LEVEL0_VECTOR
ret
!*===========================================================================*
!* data *
!*===========================================================================*
.data
patch_table: ! pairs (old function, new function)
#if ENABLE_BIOS_WINI
.data2 _bios13, p_bios13
#endif
.data2 _cp_mess, p_cp_mess
.data2 _phys_copy, p_phys_copy
.data2 portio_setup, p_portio_setup
.data2 _reset, p_reset
.data2 _level0, p_level0
.data2 _restart, p_restart ! in mpx file
.data2 save, p_save ! in mpx file
end_patch_table: ! end of table
idt_vectors: ! limit and base of real mode interrupt vectors
.data2 0x3FF
idt_zero: ! zero limit IDT to cause a processor shutdown
.data2 0, 0, 0
.bss
save_sp: ! place to put sp when switching to real mode
.space 2
msw: ! saved real mode machine status word
.space 2
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -