dono@killer.DALLAS.TX.US (Don OConnell) (01/13/89)
I personally use Turboc 1.5 and Masm 4 & 5 for doing all my Minix work. I don't know what assembler hannam is using (I think that is one that he wrote). The syntax seems to be half-way between masm and minix asld. I didn't have too much trouble porting it to masm syntax. Since I mentioned using the tty driver in posting I have received several pieces of mail asking for a minix version of klib88(I should have specified what I used in the prev. posting), and I have seen some messages in the past asking for minix ports. So I sat down and converted klib88.as -> klib88.s, it only took a couple of hours. Since I don't use minix as my development system, I can't test it and see if it works(I am trying to say that I think I did the port correctly but no guarantees). I would like it if some person more competent person(assembler wise) would check it out and make sure I didn't royally screw it up. I marked most places that I wasn't sure about with my initials "dro". ----------------------- Any way here it is ----------------------------------- |THIS TRANSLATION IS BY DON O'CONNELL [killer!dono] AND I WON'T SWEAR IT |IS A 100% GOOD BUT IT SHOULD BE CLOSE |Most of the things that I changed or added are marked as such look for "dro" |About half of the routines came directly from the klib88.s(13c) file. | I think that this is all that is needed - Don O'Connell 01-13-88 00:30:00 | This file is significantly different in code to klib88.s. It does however | perform the same functions in the same way as the original klib88. | i.e. It is largly a translation with a few optimizations. Throughout the | file the word 'INT' in the comment means to comment out the entire line to | improve interrupt latency. The 'INT' will be followed by a class letter. | E.g. INTV indicates all video routine interrupts. | This file contains a number of assembly code utility routines needed by the | kernel. They are: | phys_copy: copies data from anywhere to anywhere in memory | cp_mess: copies messages from source to destination | dma_read: transfer data between HD controller and memory | dma_write: transfer data between memory and HD controller | lock: disable interrupts | restore: restore interrupts (enable/disabled) as they were before lock() | build_sig: build 4 word structure pushed onto stack for signals | csv: procedure prolog to save the registers | cret: procedure epilog to restore the registers | get_chrome: returns 0 if display is monochrome, 1 if it is color | vid_write: write data to video ram (on color display during retrace only) | vid_fill: fill a section of video ram with a char (and attribute) | vid_fmove: move a section of video ram around (using forward copies) | vid_bmove: move a section of video ram around (using backward copies) | get_byte: reads a byte from a user program and returns it as value | put_byte: writes a byte to a user program | reboot: reboot for CTRL-ALT-DEL | wreboot: wait for character then reboot | em_xfer: read or write AT extended memory using the BIOS | The following procedures are defined in this file and called from outside it. .globl _phys_copy, _cp_mess, _lock, _restore, _em_xfer .globl _build_sig, _get_chrome, _vid_write, _vid_fill, _vid_fmove, _vid_bmove .globl _get_byte, _put_byte, _reboot, _wreboot, _dma_read, _dma_write | The following external procedure is called in this file. .globl _panic | Variables and data structures .globl _cur_proc, _proc_ptr, _vec_table, _port_65, _ps .globl _color, _vid_mask, _vid_retrace, _vid_base |*===========================================================================* |* phys_copy * |*===========================================================================* | This routine copies a block of physical memory. It is called by: | phys_copy( (long) source, (long) destination, (long) bytecount) | THIS IS STRAIGHT FROM THE 13C KLIB88.S FILE - dro _phys_copy: pushf | save flags | cli | disable interrupts cld | clear direction flag push bp | save the registers push ax | save ax push bx | save bx push cx | save cx push dx | save dx push si | save si push di | save di push ds | save ds push es | save es mov bp,sp | set bp to point to saved es L0: mov ax,28(bp) | ax = high-order word of 32-bit destination mov di,26(bp) | di = low-order word of 32-bit destination mov cx,*4 | start extracting click number from dest L1: rcr ax,*1 | click number is destination address / 16 rcr di,*1 | it is used in segment register for copy loop L1 | 4 bits of high-order word are used mov es,di | es = destination click mov ax,24(bp) | ax = high-order word of 32-bit source mov si,22(bp) | si = low-order word of 32-bit source mov cx,*4 | start extracting click number from source L2: rcr ax,*1 | click number is source address / 16 rcr si,*1 | it is used in segment register for copy loop L2 | 4 bits of high-order word are used mov ds,si | ds = source click mov di,26(bp) | di = low-order word of dest address and di,*0x000F | di = offset from paragraph # in es mov si,22(bp) | si = low-order word of source address and si,*0x000F | si = offset from paragraph # in ds mov dx,32(bp) | dx = high-order word of byte count mov cx,30(bp) | cx = low-order word of byte count test cx,#0x8000 | if bytes >= 32768, only do 32768 jnz L3 | per iteration test dx,#0xFFFF | check high-order 17 bits to see if bytes jnz L3 | if bytes >= 32768 then go to L3 jmp L4 | if bytes < 32768 then go to L4 L3: mov cx,#0x8000 | 0x8000 is unsigned 32768 L4: mov ax,cx | save actual count used in ax; needed later test cx,*0x0001 | should we copy a byte or a word at a time? jz L5 | jump if even rep | copy 1 byte at a time movb | byte copy jmp L6 | check for more bytes L5: shr cx,*1 | word copy rep | copy 1 word at a time movw | word copy L6: mov dx,32(bp) | decr count, incr src & dst, iterate if needed mov cx,30(bp) | dx || cx is 32-bit byte count xor bx,bx | bx || ax is 32-bit actual count used sub cx,ax | compute bytes - actual count sbb dx,bx | dx || cx is # bytes not yet processed or cx,cx | see if it is 0 jnz L7 | if more bytes then go to L7 or dx,dx | keep testing jnz L7 | if loop done, fall through pop es | restore all the saved registers pop ds | restore ds pop di | restore di pop si | restore si pop dx | restore dx pop cx | restore cx pop bx | restore bx pop ax | restore ax pop bp | restore bp popf | restore flags ret | return to caller L7: mov 32(bp),dx | store decremented byte count back in mem mov 30(bp),cx | as a long add 26(bp),ax | increment destination adc 28(bp),bx | carry from low-order word add 22(bp),ax | increment source adc 24(bp),bx | carry from low-order word jmp L0 | start next iteration |*===========================================================================* |* cp_mess * |*===========================================================================* | This routine is makes a fast copy of a message from anywhere in the address | 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. | It is called by: | cp_mess(src, src_clicks, src_offset, dst_clicks, dst_offset) | where all 5 parameters are shorts (16-bits). | | Note that the message size, 'Msize' is in WORDS (not bytes) and must be set | correctly. Changing the definition of message in type file and not changing | it here will lead to total disaster. | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro Msize = 12 | size of a message in 16-bit words _cp_mess: push es | save es push ds | save ds mov bx,sp | index off bx because machine can't use sp pushf | save flags cli | disable interrupts push si | save si push di | save di mov di,14(bx) | di = offset of destination buffer les si,10(bx) | use 32 bit load(ds is our base) | si = offset of source message | es = clicks of destination lds ax,6(bx) | use 32 bit load .... | ax = process number of sender | ds = clicks of source message seg es | segment override prefix mov (di),ax | copy sender's process number to dest message add si,*2 | don't copy first word add di,*2 | don't copy first word mov cx,*Msize-1 | remember, first word doesn't count cld | clear direction flag rep | iterate cx times to copy 11 words movw | copy the message pop di | restore di pop si | restore si popf | restore flags (resets interrupts to old state) pop ds | restore ds pop es | restore es ret | that's all folks! |*===========================================================================* |* dma_read * |*===========================================================================* | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _dma_read: push bp mov bp,sp push cx push dx push di push es mov cx,#256 | transfer 256 words mov dx,#0x1F0 | from/to port 1f0 cld mov es,4(bp) | segment in es mov di,6(bp) | offset in di .byte 0xF3, 0x6D | opcode for 'rep insw' pop es pop di pop dx pop cx mov sp,bp pop bp ret |*===========================================================================* |* dma_write * |*===========================================================================* | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _dma_write: push bp mov bp,sp push cx push dx push si push ds mov cx,#256 | transfer 256 words mov dx,#0x1F0 | from/to port 1f0 cld mov ds,4(bp) | segment in ds mov si,6(bp) | offset in si .byte 0xF3, 0x6F | opcode for 'rep outsw' pop ds pop si pop dx pop cx mov sp,bp pop bp ret |*===========================================================================* |* lock * |*===========================================================================* | Disable CPU interrupts. Return old psw as function value. | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _lock: pushf | save flags on stack cli | disable interrupts pop ax | return flags for restoration later ret | return to caller |*===========================================================================* |* restore * |*===========================================================================* | restore enable/disable bit to the value it had before last lock. | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _restore: push bp | save it mov bp,sp | set up base for indexing push 4(bp) | bp is the psw to be restored popf | restore flags pop bp | restore bp ret | return to caller |*===========================================================================* |* build_sig * |*===========================================================================* |* Build a structure that is pushed onto the stack for signals. It contains |* pc, psw, etc., and is machine dependent. The format is the same as generated |* by hardware interrupts, except that after the "interrupt", the signal number |* is also pushed. The signal processing routine within the user space first |* pops the signal number, to see which function to call. Then it calls the |* function. Finally, when the function returns to the low-level signal |* handling routine, control is passed back to where it was prior to the signal |* by executing a return-from-interrupt instruction, hence the need for using |* the hardware generated interrupt format on the stack. The call is: |* build_sig(sig_stuff, rp, sig) | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro | Offsets within proc table PC = 24 csreg = 18 PSW = 28 _build_sig: push bp | save bp mov bp,sp | set bp to sp for accessing params push bx | save bx push si | save si mov bx,4(bp) | bx points to sig_stuff mov si,6(bp) | si points to proc table entry mov ax,8(bp) | ax = signal number mov (bx),ax | put signal number in sig_stuff mov ax,PC(si) | ax = signalled process' PC mov 2(bx),ax | put pc in sig_stuff mov ax,csreg(si) | ax = signalled process' cs mov 4(bx),ax | put cs in sig_stuff mov ax,PSW(si) | ax = signalled process' PSW mov 6(bx),ax | put psw in sig_stuff pop si | restore si pop bx | restore bx pop bp | restore bp ret | return to caller |*===========================================================================* |* csv & cret * |*===========================================================================* | This version of csv replaces the standard one. It checks for stack overflow | within the kernel in a simpler way than is usually done. cret is standard. | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro csv: pop bx | bx = return address push bp | stack old frame pointer mov bp,sp | set new frame pointer to sp push di | save di push si | save si sub sp,ax | ax = # bytes of local variables cmp sp,splimit | has kernel stack grown too large jbe csv.1 | if sp is too low, panic jmp (bx) | normal return: copy bx to program counter csv.1: mov splimit,#0 | prevent call to panic from aborting in csv mov bx,_proc_ptr | update rp->p_splimit mov 50(bx),#0 | rp->sp_limit = 0 push _cur_proc | task number mov ax,#stkoverrun | stack overran the kernel stack area push ax | push first parameter call _panic | call is: panic(stkoverrun, cur_proc) jmp csv.1 | this should not be necessary cret: lea sp,*-4(bp) | set sp to point to saved si pop si | restore saved si pop di | restore saved di pop bp | restore bp ret | end of procedure |*===========================================================================* |* get_chrome * |*===========================================================================* | This routine calls the BIOS to find out if the display is monochrome or | color. The drivers are different, as are the video ram addresses, so we | need to know. An EGA card is a 'color' for printer ports but may display | in mono or color. A test on the result returns ... | if (get_chrome()) ... - true if color or ega card (e.g. for printer | port) | if (get_chrome()&1) ... - true if color mode, false if mono mode | if (get_chrome()&2) ... - true iff ega card _get_chrome: movb bl,*0x10 | SET UP TO CHECK IF EGA - dro movb ah,*0x12 int 0x10 | call the BIOS to get equipment type cmpb bl,*0x10 | if reg is unchanged, is not EGA je notega mov ax,#2 | ega = 2 ret | ega return notega: int 0x11 | call the BIOS to get equipment type andb al,#0x30 | isolate color/mono field cmpb al,*0x30 | 0x30 is monochrome je getchr1 | if monochrome then go to getchr1 mov ax,#1 | color = 1 ret | color return getchr1: xor ax,ax | mono = 0 ret |*===========================================================================* |* video routines (PUBLIC) * |*===========================================================================* | This routines handle writes to the screen. For a color display, the writing | only takes places during the vertical retrace interval, to avoid displaying | garbage on the screen. It will only display a maximum of vid_retrace words | in a single refresh cycle for the same reason. The display ram overflow is | handled carefully so that EGA cards work properly. These routines rely on | the stack segment being equal to the data segment. | | The calls are: | vid_write(buffer, dest, words) | vid_fill(fillw, dest, words) | vid_fmove(src, dest, words) | vid_bmove(src, dest, words) | where | 'buffer' is a pointer to the (character, attribute) pairs | 'fillw' is the word (character, attribute) for filling | 'src' tells where within video ram to copy data from | 'dest' tells where within video ram to copy the data | 'words' tells how many words to copy _vid_write: | let vidtransfer handle dest overflow push bp | set up stack frame mov bp,sp push si | save the registers push di push bx | save bx------ push cx | save cx | I think these are needed for asld push dx | save dx | dro push es | save es------ mov es,_vid_base | screen seg register call vidtransfer | do the transfer pop es | restore registers --- pop dx | restore dx | The same with these - dro pop cx | restore cx | pop bx | restore bx ---------- pop di | finished - clear stack frame pop si pop bp ret _vid_fill: | handle dest overflow explicitly push bp | set up stack frame mov bp,sp push di | save the registers push bx | save bx------ push cx | save cx | I think these are needed for asld push dx | save dx | dro push es | save es------ mov es,_vid_base | screen seg register mov ax,4(bp) | get the fill char mov di,6(bp) | get the dest call lvidfill | do the initial fill call vidcheck | check if overflow has occurred jz v1f call lvidfill | fix overflow v1f: pop es | restore registers --- pop dx | restore dx | The same with these - dro pop cx | restore cx | pop bx | restore bx ---------- pop di | finished - clear stack frame pop bp ret _vid_fmove: | handle src overflow explicitly | let vidtransfer handle dest overflow push bp | set up stack frame mov bp,sp push si | save the registers push di push ds push bx | save bx------ push cx | save cx | I think these are needed for asld push dx | save dx | dro push es | save es------ mov ax,4(bp) | src &= vid_mask and ax,_vid_mask mov 4(bp),ax add ax,8(bp) | if (src + words*2 > vid_mask) add ax,8(bp) | we have src overflow. cmp ax,_vid_mask mov es,_vid_base | set up segment registers mov ds,_vid_base jle vm2 | if src overflow then push 8(bp) | save the words count mov bx,_vid_mask | count = MIN(count, ((vid_mask+1)-src)/2) inc bx sub bx,4(bp) shr bx,#1 cmp bx,8(bp) jle vm1 mov bx,8(bp) vm1: mov 8(bp),bx | bx and count now has count to do call vidtransfer | do this first transfer mov 4(bp),#0 | set up for remaining transfer mov 6(bp),di pop 8(bp) | restore our original count sub 8(bp),bx | subtract the count done so far jz vm3 | only continue if more to do vm2: call vidtransfer | do the transfer for no src overflow vm3: pop es | restore registers --- pop dx | restore dx | The same with these - dro pop cx | restore cx | pop bx | restore bx ---------- pop ds | finished - clear stack frame pop di pop si pop bp ret _vid_bmove: | handle src overflow explicitly | let rvidtransfer handle dest overflow push bp | set up stack frame mov bp,sp push si | save the registers push di push ds push bx | save bx------ push cx | save cx | I think these are needed for asld push dx | save dx | dro push es | save es------ pushf std | transfer in reverse direction mov bx,4(bp) | src &= vid_mask and bx,_vid_mask mov 4(bp),bx mov es,_vid_base | set up segment registers mov ds,_vid_base push 8(bp) | save the total count shr bx,#1 | count = MIN(count, src/2 + 1) inc bx cmp bx,8(bp) jle vbm1 mov bx,8(bp) | also save count in bx vbm1: mov 8(bp),bx call vidrtransfer | do the transfer of non overflowing section mov ax,_vid_mask | set up to do overflow of src dec ax | convert to word address mov 4(bp),ax | new src addr pop 8(bp) | calculate count left sub 8(bp),bx jz vbm2 | if none to do don't continue call vidrtransfer | transfer overflow vbm2: popf | finished - clear stack frame pop es | restore registers --- pop dx | restore dx | The same with these - dro pop cx | restore cx | pop bx | restore bx ---------- pop ds pop di pop si pop bp ret |*===========================================================================* |* video routines (private) * |*===========================================================================* | The following video support routines may be changed in thier interrupt | handling methods. If a glitch due to an interrupt during screen writes | is acceptable then comment out all lines with 'INTV' in thier comment. | Doing this improves interrupt latency (e.g. for RS232 throughput). In | practice I have never seen any glitches with the interrupts on. vidtransfer: | transfer a block to the screen (forward dir) | handle dest overflow | final results returned in si, di mov si,4(bp) | si = pointer to data to be copied mov di,6(bp) | di = offset within video ram call lvidcopy | write the block to the screen call vidcheck | check for video ram (window) overflow jz vt1 sub si,8(bp) | overflow - find buffer position sub si,8(bp) call lvidcopy | fix up overflow vt1: ret vidrtransfer: | transfer a block to the screen (reverse dir) | handle dest overflow | final results in stack frame mov si,4(bp) | si = pointer to data to be copied mov di,6(bp) | di = offset within video ram call lvidcopy | write the block to the screen call vidrcheck | check for video ram (window) overflow xchg si,4(bp) | get orig src & dest , save final src dest xchg di,6(bp) jz vr1 and di,_vid_mask | address the overflow block call lvidcopy | write the overflow block vr1: ret lvidcopy: | Transfer a block to the screen in sub-blocks | with a maximum of vid_retrace words per sub-block. mov cx,_vid_retrace | cx = MIN(count, vid_retrace) cmp cx,8(bp) jle lvc1 mov cx,8(bp) lvc1: jcxz lvc2 | only do transfer if cx != 0 sub 8(bp),cx | count -= cx call vidcopy jmp lvidcopy | get the next sub-block lvc2: ret lvidfill: | Fill a block on the screen in sub-blocks | with a maximum of vid_retrace words per sub-block. mov cx,_vid_retrace | cx = MIN(count, vid_retrace) cmp cx,8(bp) jle lvf1 mov cx,8(bp) lvf1: jcxz lvf2 | only do transfer if cx != 0 sub 8(bp),cx | count -= cx call vidfill jmp lvidfill | get the next sub-block lvf2: ret vidcopy: | Transfer a sub-block to the screen waiting for | retrace if necessary. call vidwait | wait for retrace if necessary rep | I THINK THAT THIS IS HOW THESE ARE WRITTEN movw | transfer the block | IN ASLD SYNTAX - dro | push ax | INTV restore the flags | popf | INTV ret vidfill: | Fill a sub-block on the screen waiting for | retrace if necessary. push ax | save the fill char call vidwait | wait for retrace if necessary | mov dx,ax | INTV save the flags pop ax | restore the fill char rep | SAME FOR THIS ONE - dro stow | do the fill | push dx | INTV restore the flags | popf | INTV ret vidwait: | Wait for retrace only if necessary test _color,*1 | mono's don't need retrace checking jz vw2 test _color,*2 | ega's don't need retrace checking jnz vw2 mov dx,#3DAH | port for retrace status | pushf | INTV vw1: | sti | INTV ensure interrupts can have a go | nop | INTV | nop | INTV | cli | INTV in | wait for retrace on (orig. -- in al,[dx] -- dro) testb al,*8 jz vw1 | pop ax | INTV return the flags in ax (ints off) vw2: ret vidcheck: | Check if the forward transfer just completed | requires overflow fixing on dest. If so set up | di and count. count = 0 on entry mov dx,di | dx = final dest sub dx,_vid_mask | see if overflowed sub dx,#1 | must do sub as dec doesn't set flag jle vck2 | if so x = overflow count sub di,6(bp) | count = MIN(dx, final dest - init dest) cmp di,dx jle vck1 mov di,dx vck1: mov 8(bp),di | save the new count sub dx,di | new dest = overflow count - new count mov di,dx vck2: shr 8(bp),*1 | turn byte count to word count & test ret | if any work done. vidrcheck: | Check if the backward transfer just completed | requires overflow fixing on dest. If so set up | count. count = 0 on entry mov dx,6(bp) | dx = final dest sub dx,_vid_mask | see if overflowed sub dx,#1 | must do sub as dec doesn't set flag jle vrck2 | if so dx = overflow count mov ax,6(bp) | count = MIN(dx, final dest - init dest) sub ax,di cmp ax,dx jle vrck1 mov ax,dx vrck1: mov 8(bp),ax | save the new count vrck2: shr 8(bp),*1 | turn byte count to word count & test ret | if any work done. |*===========================================================================* |* get_byte * |*===========================================================================* | This routine is used to fetch a byte from anywhere in memory. | The call is: | c = get_byte(seg, off) | where | 'seg' is the value to put in es | 'off' is the offset from the es value | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _get_byte: push bp | save bp mov bp,sp | we need to access parameters push es | save es mov es,4(bp) | load es with segment value mov bx,6(bp) | load bx with offset from segment seg es | go get the byte movb al,(bx) | al = byte xorb ah,ah | ax = byte pop es | restore es pop bp | restore bp ret | return to caller |*===========================================================================* |* put_byte * |*===========================================================================* | This routine is used to put a byte anywhere in memory. | The call is: | retval = put_byte(seg, off, val) | where | 'seg' is the value to put in es | 'off' is the offset from the es value | 'val' is value to put in memory | 'retval' = val & 0xFF _put_byte: push bp | save bp mov bp,sp | we need to access parameters push es | save es movb al,8(bp) | load al with value mov es,4(bp) | load es with segment value mov bx,6(bp) | load bx with offset from segment seg es | go get the byte movb (bx),al | put the byte xorb ah,ah | ax = byte pop es | restore es pop bp | restore bp ret | return to caller |*===========================================================================* |* reboot & wreboot * |*===========================================================================* | This code reboots the PC | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro _reboot: cli | disable interrupts mov ax,#0x20 | re-enable interrupt controller out 0x20 call resvec | restore the vectors in low core mov ax,#0x40 push ds mov ds,ax mov ax,#0x1234 mov 0x72,ax pop ds test _ps,#0xFFFF jnz r.1 mov ax,#0xFFFF mov ds,ax mov ax,3 push ax mov ax,1 push ax reti r.1: mov ax,_port_65 | restore port 0x65 mov dx,#0x65 out mov dx,#0x21 | restore interrupt mask port mov ax,#0xBC out sti | enable interrupts int 0x19 | for PS/2 call bios to reboot _wreboot: cli | disable interrupts mov ax,#0x20 | re-enable interrupt controller out 0x20 call _eth_stp | stop the ethernet chip call resvec | restore the vectors in low core xor ax,ax | wait for character before continuing int 0x16 | get char mov ax,#0x40 push ds mov ds,ax mov ax,#0x1234 mov 0x72,ax pop ds test _ps,#0xFFFF jnz wr.1 mov ax,#0xFFFF mov ds,ax mov ax,3 push ax mov ax,1 push ax reti wr.1: mov ax,_port_65 | restore port 0x65 mov dx,#0x65 out mov dx,#0x21 | restore interrupt mask port mov ax,#0xBC out sti | enable interrupts int 0x19 | for PS/2 call bios to reboot | Restore the interrupt vectors in low core. resvec: cld mov cx,#2*71 mov si,#_vec_table xor di,di mov es,di rep movw mov ax,tty_vec1 | Restore keyboard interrupt vector for PS/2 seg es mov 452,ax mov ax,tty_vec2 seg es mov 454,ax ret | Some library routines use exit, so this label is needed. | Actual calls to exit cannot occur in the kernel. .globl _exit _exit: sti jmp _exit |=========================================================================== | em_xfer |=========================================================================== | | This file contains one routine which transfers words between user memory | and extended memory on an AT or clone. A BIOS call (INT 15h, Func 87h) | is used to accomplish the transfer. | | This particular BIOS routine runs with interrupts off since the 80286 | must be placed in protected mode to access the memory above 1 Mbyte. | So there should be no problems using the BIOS call. | | THIS IS TAKEN DIRECTLY FROM THE 13C KLIB88.S FILE - dro .text gdt: | Begin global descriptor table | Dummy descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | descriptor for GDT itself .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved src: | source descriptor srcsz: .word 0 | segment length (limit) srcl: .word 0 | bits 15-0 of physical address srch: .byte 0 | bits 23-16 of physical address .byte 0x93 | access rights byte .word 0 | reserved tgt: | target descriptor tgtsz: .word 0 | segment length (limit) tgtl: .word 0 | bits 15-0 of physical address tgth: .byte 0 | bits 23-16 of physical address .byte 0x93 | access rights byte .word 0 | reserved | BIOS CS descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | stack segment descriptor .word 0 | segment length (limit) .word 0 | bits 15-0 of physical address .byte 0 | bits 23-16 of physical address .byte 0 | access rights byte .word 0 | reserved | | | Execute a transfer between user memory and extended memory. | | status = em_xfer(source, dest, count); | | Where: | status => return code (0 => OK) | source => Physical source address (32-bit) | dest => Physical destination address (32-bit) | count => Number of words to transfer | | | _em_xfer: push bp | Save registers mov bp,sp push si push es push cx | | Pick up source and destination addresses and update descriptor tables | mov ax,4(bp) seg cs mov srcl,ax mov ax,6(bp) seg cs movb srch,al mov ax,8(bp) seg cs mov tgtl,ax mov ax,10(bp) seg cs movb tgth,al | | Update descriptor table segment limits | mov cx,12(bp) mov ax,cx add ax,ax seg cs mov tgtsz,ax seg cs mov srcsz,ax | | Now do actual DOS call | push cs pop es seg cs mov si,#gdt movb ah,#0x87 pushf int 0x15 | Do a far call to BIOS routine | | All done, return to caller. | pop cx | restore registers pop es pop si mov sp,bp pop bp ret .data vidlock: .word 0 | dummy variable for use with lock prefix splimit: .word 0 | stack limit for current task (kernel only) tmp: .word 0 | count of bytes already copied stkoverrun: .asciz "Kernel stack overrun, task = " _vec_table: .zerow 284 | storage for interrupt vectors tty_vec1: .word 0 | sorage for vector 0x71 (offset) tty_vec2: .word 0 | sorage for vector 0x71 (segment)