📄 klib88.s
字号:
#
#include <minix/config.h>
#include <minix/const.h>
#include "const.h"
#include "sconst.h"
#include "protect.h"
! This file contains a number of assembly code utility routines needed by the
! kernel. They are:
.define _monitor ! exit Minix and return to the monitor
.define real2prot ! switch from real to protected mode
.define prot2real ! switch from protected to real mode
.define _check_mem ! check a block of memory, return the valid size
.define _cp_mess ! copies messages from source to destination
.define _exit ! dummy for library routines
.define __exit ! dummy for library routines
.define ___exit ! dummy for library routines
.define .fat, .trp ! dummies for library routines
.define _in_byte ! read a byte from a port and return it
.define _in_word ! read a word from a port and return it
.define _out_byte ! write a byte to a port
.define _out_word ! write a word to a port
.define _port_read ! transfer data from (disk controller) port to memory
.define _port_read_byte ! likewise byte by byte
.define _port_write ! transfer data from memory to (disk controller) port
.define _port_write_byte ! likewise byte by byte
.define _lock ! disable interrupts
.define _unlock ! enable interrupts
.define _enable_irq ! enable an irq at the 8259 controller
.define _disable_irq ! disable an irq
.define _phys_copy ! copy data from anywhere to anywhere in memory
.define _mem_rdw ! copy one word from [segment:offset]
.define _reset ! reset the system
.define _mem_vid_copy ! copy data to video ram
.define _vid_vid_copy ! move data in video ram
.define _level0 ! call a function at level 0
.define klib_init_prot ! initialize klib functions for protected mode
! The routines only guarantee to preserve the registers the C compiler
! expects to be preserved (si, di, bp, sp, segment registers, and direction
! bit in the flags), though some of the older ones preserve bx, cx and dx.
#define DS_286_OFFSET DS_286_INDEX*DESC_SIZE
#define ES_286_OFFSET ES_286_INDEX*DESC_SIZE
# define EM_XFER_FUNC 0x87
#define JMP_OPCODE 0xE9 /* opcode used for patching */
#define OFF_MASK 0x000F /* offset mask for phys_b -> hclick:offset */
#define HCHIGH_MASK 0x0F /* h/w click mask for low byte of hi word */
#define HCLOW_MASK 0xF0 /* h/w click mask for low byte of low word */
! Imported functions
.extern p_restart
.extern p_save
.extern _restart
.extern save
! Exported variables
.extern kernel_cs
! Imported variables
.extern kernel_ds
.extern _irq_use
.extern _blank_color
.extern _gdt
.extern _protected_mode
.extern _vid_seg
.extern _vid_size
.extern _vid_mask
.extern _level0_func
.text
!*===========================================================================*
!* monitor *
!*===========================================================================*
! PUBLIC void monitor();
! Return to the monitor.
_monitor:
call prot2real ! switch to real mode
mov ax, _reboot_code+0 ! address of new parameters
mov dx, _reboot_code+2
mov sp, _mon_sp ! restore monitor stack pointer
mov bx, _mon_ss ! monitor data segment
mov ds, bx
mov es, bx
mov ss, bx
pop di
pop si
pop bp
retf ! return to the monitor
#if ENABLE_BIOS_WINI
!*===========================================================================*
!* bios13 *
!*===========================================================================*
! PUBLIC void bios13();
.define _bios13
_bios13: ! make a BIOS 0x13 call for disk I/O
push si
push di ! save C variable registers
pushf ! save flags
call int13 ! make the actual call
popf ! restore flags
pop di ! restore C registers
pop si
ret
! Make a BIOS 0x13 call from protected mode
p_bios13:
push bp
push si
push di ! save C variable registers
pushf ! save flags
cli ! no interruptions
inb INT2_CTLMASK
movb ah, al
inb INT_CTLMASK
push ax ! save interrupt masks
mov ax, _irq_use ! map of in-use IRQs
and ax, #~[1<<CLOCK_IRQ] ! there is a special clock handler
outb INT_CTLMASK ! enable all unused IRQs and vv.
movb al, ah
outb INT2_CTLMASK
smsw ax
push ax ! save machine status word
call prot2real ! switch to real mode
call int13 ! make the actual call
call real2prot ! back to protected mode
pop ax
lmsw ax ! restore msw
pop ax ! restore interrupt masks
outb INT_CTLMASK
movb al, ah
outb INT2_CTLMASK
popf ! restore flags
pop di
pop si
pop bp ! restore C variable registers
ret
int13:
mov ax, _Ax ! load parameters
mov bx, _Bx
mov cx, _Cx
mov dx, _Dx
mov es, _Es
sti ! enable interrupts
int 0x13 ! make the BIOS call
cli ! disable interrupts
mov _Ax, ax ! save results
mov _Bx, bx
mov _Cx, cx
mov _Dx, dx
mov _Es, es
mov ax, ds
mov es, ax ! restore es
ret
.bss
.define _Ax, _Bx, _Cx, _Dx, _Es ! 8086 register variables
.comm _Ax, 2
.comm _Bx, 2
.comm _Cx, 2
.comm _Dx, 2
.comm _Es, 2
.text
#endif /* ENABLE_BIOS_WINI */
!*===========================================================================*
!* real2prot *
!*===========================================================================*
! Switch from real to protected mode.
real2prot:
lgdt _gdt+GDT_SELECTOR ! set global descriptor table
smsw ax
mov msw, ax ! save real mode msw
orb al, #0x01 ! set PE (protection enable) bit
lmsw ax ! set msw, enabling protected mode
jmpf csinit, CS_SELECTOR ! set code segment selector
csinit:
mov ax, #DS_SELECTOR ! set data selectors
mov ds, ax
mov es, ax
mov ss, ax
lidt _gdt+IDT_SELECTOR ! set interrupt vectors
andb _gdt+TSS_SELECTOR+DESC_ACCESS, #~0x02 ! clear TSS busy bit
mov ax, #TSS_SELECTOR
ltr ax ! set TSS register
movb ah, #0xDF
jmp gate_A20 ! enable the A20 address line
!*===========================================================================*
!* prot2real *
!*===========================================================================*
! Switch from protected to real mode.
prot2real:
mov save_sp, sp ! save stack pointer
cmp _processor, #386 ! is this a 386?
jae p2r386
p2r286:
mov _gdt+ES_286_OFFSET+DESC_BASE, #0x0400
movb _gdt+ES_286_OFFSET+DESC_BASE_MIDDLE, #0x00
mov ax, #ES_286_SELECTOR
mov es, ax ! BIOS data segment
eseg mov 0x0067, #real ! set return from shutdown address
cseg mov ax, kernel_cs
eseg mov 0x0069, ax
movb al, #0x8F
outb 0x70 ! select CMOS byte 0x0F (disable NMI)
jmp .+2
movb al, #0x0A
outb 0x71 ! set shutdown code to 0x0A "jump far"
jmp p_reset ! cause a processor shutdown
p2r386:
lidt idt_vectors ! real mode interrupt vectors
push _gdt+CS_SELECTOR+0
push _gdt+DS_SELECTOR+0 ! save CS and DS limits
mov _gdt+CS_SELECTOR+0, #0xFFFF
mov _gdt+DS_SELECTOR+0, #0xFFFF ! set 64k limits
jmpf cs64k, CS_SELECTOR ! reload selectors
cs64k: mov ax, #DS_SELECTOR
mov ds, ax
mov es, ax
mov ss, ax
pop _gdt+DS_SELECTOR+0
pop _gdt+CS_SELECTOR+0 ! restore CS and DS limits
.data1 0x0F,0x20,0xC0 ! mov eax, cr0
mov ax, msw ! restore real mode (16 bits) msw
.data1 0x0F,0x22,0xC0 ! mov cr0, eax
.data1 0xEA ! jmpf real, "kernel_cs"
.data2 real
kernel_cs:
.data2 0
real:
cseg mov ax, kernel_ds ! reload data segment registers
mov ds, ax
mov es, ax
mov ss, ax
mov sp, save_sp ! restore stack
movb ah, #0xDD
!jmp gate_A20 ! disable the A20 address line
! Enable (ah = 0xDF) or disable (ah = 0xDD) the A20 address line.
gate_A20:
call kb_wait
movb al, #0xD1 ! Tell keyboard that a command is coming
outb 0x64
call kb_wait
movb al, ah ! Enable or disable code
outb 0x60
call kb_wait
mov ax, #25 ! 25 microsec delay for slow keyboard chip
0: out 0xED ! Write to an unused port (1us)
dec ax
jne 0b
ret
kb_wait:
inb 0x64
testb al, #0x02 ! Keyboard input buffer full?
jnz kb_wait ! If so, wait
ret
!*===========================================================================*
!* check_mem *
!*===========================================================================*
! PUBLIC phys_bytes check_mem(phys_bytes base, phys_bytes size);
! Check a block of memory, return the amount valid.
! Only every 16th byte is checked.
! This only works in protected mode.
! An initial size of 0 means everything.
! This really should do some alias checks.
PCM_DENSITY = 256 ! resolution of check
! the shift logic depends on this being 256
TEST1PATTERN = 0x55 ! memory test pattern 1
TEST2PATTERN = 0xAA ! memory test pattern 2
_check_mem:
pop bx
pop _gdt+DS_286_OFFSET+DESC_BASE
pop ax ! pop base into base of source descriptor
movb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE,al
pop cx ! byte count in dx:cx
pop dx
sub sp,#4+4
push bx
push ds
sub ax,ax ! prepare for early exit
test dx,#0xFF00
jnz cm_1exit ! cannot handle bases above 16M
movb cl,ch ! divide size by 256 and discard high byte
movb ch,dl
push cx ! save divided size
sub bx,bx ! test bytes at bases of segments
cm_loop:
mov ax,#DS_286_SELECTOR
mov ds,ax
movb dl,#TEST1PATTERN
xchgb dl,(bx) ! write test pattern, remember original value
xchgb dl,(bx) ! restore original value, read test pattern
cmpb dl,#TEST1PATTERN ! must agree if good real memory
jnz cm_exit ! if different, memory is unusable
movb dl,#TEST2PATTERN
xchgb dl,(bx)
xchgb dl,(bx)
cmpb dl,#TEST2PATTERN
jnz cm_exit
! next segment, test for wraparound at 16M
! assuming es == old ds
eseg add _gdt+DS_286_OFFSET+DESC_BASE,#PCM_DENSITY
eseg adcb _gdt+DS_286_OFFSET+DESC_BASE_MIDDLE,#0
loopnz cm_loop
cm_exit:
pop ax
sub ax,cx ! verified size in multiples of PCM_DENSITY
cm_1exit:
movb dl,ah ! convert to phys_bytes in dx:ax
subb dh,dh
movb ah,al
movb al,dh
pop ds
ret
!*===========================================================================*
!* cp_mess *
!*===========================================================================*
! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
! phys_clicks dst_clicks, vir_bytes dst_offset);
! This routine makes a fast copy of a message from anywhere in the address
! space to anywhere else. It also copies the source address provided as a
! parameter to the call into the first word of the destination message.
!
! Note that the message size, "Msize" is in WORDS (not bytes) and must be set
! correctly. Changing the definition of message in the type file and not
! changing it here will lead to total disaster.
_cp_mess:
cld
push es ! save es
push ds ! save ds
mov bx,sp ! index off bx because machine cannot use sp
push si ! save si
push di ! save di
mov ax,12(bx) ! destination click
#if HCLICK_SHIFT > CLICK_SHIFT
#error /* Small click sizes are not supported (right shift will lose bits). */
#endif
#if HCLICK_SHIFT < CLICK_SHIFT
movb cl,#CLICK_SHIFT-HCLICK_SHIFT
shl ax,cl ! destination segment
#endif
mov es,ax
mov di,14(bx) ! offset of destination message
! Be careful not to destroy ds before we are finished with the bx pointer.
! We are using bx and not the more natural bp to save pushing bp.
mov ax,6(bx) ! process number of sender
mov si,10(bx) ! offset of source message
mov bx,8(bx) ! source click (finished with bx as a pointer)
#if HCLICK_SHIFT < CLICK_SHIFT
shl bx,cl ! source segment
#endif
mov ds,bx
stos ! copy process number of sender to dest message
add si,*2 ! do not copy first word
mov cx,*Msize-1 ! remember, first word does not count
rep ! iterate cx times to copy 11 words
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -