Added 8086 PC bootable floppy support (pc86).
This commit is contained in:
parent
1c7bb87041
commit
df153ba299
15 changed files with 1028 additions and 0 deletions
41
plat/pc86/README
Normal file
41
plat/pc86/README
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
# $Source$
|
||||||
|
# $State$
|
||||||
|
|
||||||
|
The pc86 platform
|
||||||
|
=================
|
||||||
|
|
||||||
|
pc86 is an i86-based BSP that produces bootable floppy disk images that can
|
||||||
|
be run on most PCs. It is intended to be quick and dirty rather than actually
|
||||||
|
useful, although it may come in handy for hardware test purposes, boot
|
||||||
|
loaders, and the like.
|
||||||
|
|
||||||
|
The code runs in TINY mode, where CS, DS and SS all share the same segment.
|
||||||
|
This means that there's not very much memory available. It would be very easy
|
||||||
|
to change it to run in SMALL mode, where CS occupies one segment and DS and SS
|
||||||
|
another, which would give 64kB for nearly all programs; I just haven't done it.
|
||||||
|
|
||||||
|
This port uses a syscall interface, which means you get *all* of the ACK's
|
||||||
|
builtin libc with no shortcuts. File descriptors 0, 1 and 2 represent the
|
||||||
|
console. All reads block. There's enough TTY emulation to allow \n conversion
|
||||||
|
(set RAW to turn off) and local echo (unset ECHO to turn off); this is needed
|
||||||
|
to make Basic work.
|
||||||
|
|
||||||
|
Language support
|
||||||
|
================
|
||||||
|
|
||||||
|
Tested with C (both), Basic, Pascal, Occam, Modula-2.
|
||||||
|
|
||||||
|
Basic works, but because Basic programs require access to a data file to work,
|
||||||
|
and pc86 doesn't (of course) have a file system, programs won't start unless
|
||||||
|
you hack the compiler not to try and open it.
|
||||||
|
|
||||||
|
Example command line
|
||||||
|
====================
|
||||||
|
|
||||||
|
ack -mpc86 -O -ansi -o pc86.img test.c
|
||||||
|
|
||||||
|
The file pc86.img can then be copied onto a floppy and booted, or run via qemu
|
||||||
|
or somesuch emulator.
|
||||||
|
|
||||||
|
David Given
|
||||||
|
dg@cowlark.com
|
321
plat/pc86/boot.s
Normal file
321
plat/pc86/boot.s
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
! Some definitions.
|
||||||
|
|
||||||
|
BOOT_SEGMENT = 0x07C0 ! Where we've been loaded
|
||||||
|
|
||||||
|
#define PRINT(N) push ax; push bx; movb ah, 0x0E; movb al, N; mov bx, 0x0007; int 0x10; pop bx; pop ax
|
||||||
|
|
||||||
|
begtext:
|
||||||
|
! This code makes up the PC boot sector, and is the first thing on the
|
||||||
|
! floppy disk. The PC will load this sector to 0x07C0:0000 and jump to it
|
||||||
|
! with dl set to our drive, but it won't necessarily do it in a sane way
|
||||||
|
! (some BIOSes jump to 0x0000:7C00 instead). So, we need to fix that.
|
||||||
|
|
||||||
|
jmpf BOOT_SEGMENT : start2
|
||||||
|
start2:
|
||||||
|
! Set up the segment descriptors. We're running in tiny mode, so it's just
|
||||||
|
! a matter of copying the contents of cs (already been set up by the jmpf)
|
||||||
|
! into the other registers.
|
||||||
|
|
||||||
|
mov ax, cs
|
||||||
|
mov ds, ax
|
||||||
|
mov es, ax
|
||||||
|
mov ss, ax
|
||||||
|
|
||||||
|
! Initialise the stack, which will start at the top of our segment and work
|
||||||
|
! down.
|
||||||
|
|
||||||
|
mov sp, 0 ! the first push will wrap round to 0xFFFF
|
||||||
|
|
||||||
|
! Some more startup housekeeping.
|
||||||
|
|
||||||
|
sti
|
||||||
|
cld
|
||||||
|
|
||||||
|
! We're now set up for actual code. Write out our banner. Remember that
|
||||||
|
! at this point dl contains our drive number, which we want to keep.
|
||||||
|
|
||||||
|
mov si, banner_msg
|
||||||
|
call write_string
|
||||||
|
|
||||||
|
! Probe the drive to figure out its geometry.
|
||||||
|
|
||||||
|
push dx
|
||||||
|
mov ax, 0x0800 ! service number
|
||||||
|
int 0x13
|
||||||
|
pop ax
|
||||||
|
jc cant_boot
|
||||||
|
|
||||||
|
! At this point:
|
||||||
|
! al: current drive
|
||||||
|
! cl: maximum sector number (bottom six bits)
|
||||||
|
! dh: maximum head number
|
||||||
|
! We don't care about the rest.
|
||||||
|
andb cl, 0x3F
|
||||||
|
|
||||||
|
! We now need to go through a loop loading each sector in turn.
|
||||||
|
! During this loop, the registers will be set up as follows:
|
||||||
|
! al: current cylinder
|
||||||
|
! ah: maximum head
|
||||||
|
! bx: address
|
||||||
|
! cl: current sector (one based)
|
||||||
|
! ch: maximum sector (one based)
|
||||||
|
! dl: current drive
|
||||||
|
! dh: current head
|
||||||
|
! Why, yes, they are painstakingly shoehorned in to get all the data
|
||||||
|
! into registers.
|
||||||
|
|
||||||
|
movb dl, al
|
||||||
|
movb ch, cl
|
||||||
|
movb ah, dh
|
||||||
|
movb al, 0 ! start on cylinder 0
|
||||||
|
mov bx, 0x0200 ! don't overwrite boot sector
|
||||||
|
movb cl, 2 ! start on sector 2 (skip boot sector)
|
||||||
|
movb dh, 0 ! start on head 0
|
||||||
|
|
||||||
|
1:
|
||||||
|
call read_sector
|
||||||
|
|
||||||
|
! Next memory area.
|
||||||
|
|
||||||
|
add bx, 0x0200
|
||||||
|
cmp bx, enddata
|
||||||
|
ja finished
|
||||||
|
|
||||||
|
! Next sector.
|
||||||
|
|
||||||
|
incb cl
|
||||||
|
cmpb cl, ch
|
||||||
|
jle 1b
|
||||||
|
movb cl, 1 ! back to sector 1 again
|
||||||
|
|
||||||
|
! Next head.
|
||||||
|
|
||||||
|
incb dh
|
||||||
|
cmpb dh, ah
|
||||||
|
jle 1b
|
||||||
|
movb dh, 0 ! back to head 1 again
|
||||||
|
|
||||||
|
! Next cylinder.
|
||||||
|
|
||||||
|
incb al
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
cant_boot:
|
||||||
|
mov si, bootfail_msg
|
||||||
|
call write_string
|
||||||
|
jmp EXIT
|
||||||
|
|
||||||
|
! Reads a sector into memory. The parameters are:
|
||||||
|
! al: cylinder
|
||||||
|
! bx: address
|
||||||
|
! cl: sector
|
||||||
|
! dl: drive
|
||||||
|
! dh: head
|
||||||
|
! If an error occurs, it'll automatically try again. And again.
|
||||||
|
! And again...
|
||||||
|
|
||||||
|
read_sector:
|
||||||
|
push ax
|
||||||
|
push bx
|
||||||
|
push cx
|
||||||
|
push dx
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
push dx
|
||||||
|
xorb dh, dh
|
||||||
|
movb dl, cl
|
||||||
|
call write_hex4
|
||||||
|
pop dx
|
||||||
|
PRINT(0x20)
|
||||||
|
push dx
|
||||||
|
movb dl, dh
|
||||||
|
xorb dh, dh
|
||||||
|
call write_hex4
|
||||||
|
pop dx
|
||||||
|
PRINT(0x20)
|
||||||
|
push dx
|
||||||
|
movb dl, al
|
||||||
|
xorb dh, dh
|
||||||
|
call write_hex4
|
||||||
|
pop dx
|
||||||
|
#endif
|
||||||
|
|
||||||
|
1:
|
||||||
|
movb ch, al
|
||||||
|
mov ax, 0x0201 ! service 2, read one sector
|
||||||
|
int 0x13
|
||||||
|
jc 2f
|
||||||
|
|
||||||
|
mov ax, 0x0E2E ! write out a .
|
||||||
|
mov bx, 0x0007 ! page 0, white
|
||||||
|
int 0x10
|
||||||
|
|
||||||
|
pop dx
|
||||||
|
pop cx
|
||||||
|
pop bx
|
||||||
|
pop ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
! If a read fail occurs, the spec (such as it is) states that we need
|
||||||
|
! to reset the fd controller and try again.
|
||||||
|
2:
|
||||||
|
push ax
|
||||||
|
push bx
|
||||||
|
|
||||||
|
mov ax, 0x0E21 ! write out a !
|
||||||
|
mov bx, 0x0007 ! page 0, white
|
||||||
|
int 0x10
|
||||||
|
|
||||||
|
mov ax, 0x0000
|
||||||
|
int 0x13
|
||||||
|
|
||||||
|
pop bx
|
||||||
|
pop ax
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
! Waits for a keystroke (and then discards it).
|
||||||
|
|
||||||
|
pause:
|
||||||
|
push ax
|
||||||
|
xorb ah, ah
|
||||||
|
int 0x16
|
||||||
|
pop ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
! This utility writes the string pointed to by ds:si out to the console.
|
||||||
|
|
||||||
|
write_string:
|
||||||
|
push ax
|
||||||
|
push bx
|
||||||
|
1:
|
||||||
|
lodsb
|
||||||
|
andb al, al
|
||||||
|
jz 2f
|
||||||
|
movb ah, 0xE ! service
|
||||||
|
mov bx, 0x0007 ! page 0, white
|
||||||
|
int 0x10
|
||||||
|
jmp 1b
|
||||||
|
2:
|
||||||
|
pop bx
|
||||||
|
pop ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
! Writes out the contents of dx as hex.
|
||||||
|
|
||||||
|
write_hex4:
|
||||||
|
push ax
|
||||||
|
push cx
|
||||||
|
mov cx, 4 ! 4 hex digits
|
||||||
|
1:
|
||||||
|
rol dx, 1 ! rotate so that highest 4 bits are at the bottom
|
||||||
|
rol dx, 1
|
||||||
|
rol dx, 1
|
||||||
|
rol dx, 1
|
||||||
|
mov ax, 0xE0F ! ah = request, al = mask for nybble
|
||||||
|
andb al, dl
|
||||||
|
addb al, 0x90 ! convert al to ascii hex (four instructions)
|
||||||
|
daa
|
||||||
|
adcb al, 0x40
|
||||||
|
daa
|
||||||
|
int 0x10
|
||||||
|
loop 1b
|
||||||
|
pop cx
|
||||||
|
pop ax
|
||||||
|
ret
|
||||||
|
|
||||||
|
! Everything loaded successfully!
|
||||||
|
!
|
||||||
|
! We now need to do some setup and start the program itself.
|
||||||
|
|
||||||
|
finished:
|
||||||
|
mov si, running_msg
|
||||||
|
call write_string
|
||||||
|
call pause
|
||||||
|
|
||||||
|
! Wipe the bss. (I'm a little suprised that __m_a_i_n doesn't do this.)
|
||||||
|
|
||||||
|
mov di, begbss
|
||||||
|
mov cx, endbss
|
||||||
|
sub cx, di
|
||||||
|
mov ax, 0
|
||||||
|
rep stosb
|
||||||
|
|
||||||
|
! Push standard parameters onto the stack and go.
|
||||||
|
|
||||||
|
mov ax, 1
|
||||||
|
push ax ! argc
|
||||||
|
mov ax, 2
|
||||||
|
push ax ! argc
|
||||||
|
mov ax, 3
|
||||||
|
push ax ! envp
|
||||||
|
call __m_a_i_n
|
||||||
|
! fall through into the exit routine.
|
||||||
|
|
||||||
|
! Halts, waits for a keypress, and reboots. This also becomes the
|
||||||
|
! application termination routine.
|
||||||
|
|
||||||
|
.define __exit
|
||||||
|
.extern __exit
|
||||||
|
.define EXIT
|
||||||
|
.extern EXIT
|
||||||
|
__exit:
|
||||||
|
EXIT:
|
||||||
|
mov si, halted_msg
|
||||||
|
call write_string
|
||||||
|
|
||||||
|
1:
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
xor ax, ax
|
||||||
|
int 0x16 ! get key
|
||||||
|
int 0x19 ! reboot
|
||||||
|
|
||||||
|
! Some text messages.
|
||||||
|
|
||||||
|
banner_msg: .asciz 'ACKBOOT\n\r'
|
||||||
|
nl_msg = banner_msg + 7 ! cheap trick
|
||||||
|
|
||||||
|
bootfail_msg: .asciz 'Unable to boot!\n\r'
|
||||||
|
loading_msg: .asciz '\n\rLoading...\n\r'
|
||||||
|
halted_msg: .asciz '\n\rHalted.\n\r'
|
||||||
|
running_msg: .asciz '\n\rRunning.\n\r'
|
||||||
|
|
||||||
|
! ...and we need this to fool the PC into booting our boot sector.
|
||||||
|
|
||||||
|
.align 510
|
||||||
|
.data2 0xAA55
|
||||||
|
|
||||||
|
|
||||||
|
.define begtext,begdata,begbss
|
||||||
|
.define hol0,.trppc,.ignmask
|
||||||
|
.define ERANGE,ESET,EHEAP,ECASE,EILLINS,EIDIVZ,EODDZ
|
||||||
|
.extern _end
|
||||||
|
|
||||||
|
.sect .data
|
||||||
|
hol0:
|
||||||
|
.data2 0,0
|
||||||
|
.data2 0,0
|
||||||
|
.ignmask:
|
||||||
|
.data2 0
|
||||||
|
.trppc:
|
||||||
|
.data2 0
|
||||||
|
|
||||||
|
! Define symbols at the beginning of our various segments, so that we can find
|
||||||
|
! them. (Except .text, which has already been done.)
|
||||||
|
|
||||||
|
.sect .data; begdata:
|
||||||
|
.sect .rom; begrom:
|
||||||
|
.sect .bss; begbss:
|
67
plat/pc86/descr
Normal file
67
plat/pc86/descr
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# $Revision$
|
||||||
|
var w=2
|
||||||
|
var p=2
|
||||||
|
var s=2
|
||||||
|
var l=4
|
||||||
|
var f=4
|
||||||
|
var d=8
|
||||||
|
var ARCH=i86
|
||||||
|
var PLATFORM=pc86
|
||||||
|
var PLATFORMDIR={EM}/lib/{PLATFORM}
|
||||||
|
var CPP_F=-D__unix
|
||||||
|
var ALIGN=-a0:1 -a1:1 -a2:1 -a3:1
|
||||||
|
var C_LIB={PLATFORMDIR}/tail_cc.1s {PLATFORMDIR}/tail_cc.2g
|
||||||
|
var OLD_C_LIB={C_LIB}
|
||||||
|
var MACHOPT_F=-m8
|
||||||
|
name be
|
||||||
|
from .m.g
|
||||||
|
to .s
|
||||||
|
program {EM}/lib.bin/{PLATFORM}/ncg
|
||||||
|
args <
|
||||||
|
stdout
|
||||||
|
need .e
|
||||||
|
end
|
||||||
|
name as
|
||||||
|
from .s.so
|
||||||
|
to .o
|
||||||
|
program {EM}/lib.bin/{PLATFORM}/as
|
||||||
|
args - -o > <
|
||||||
|
prep cond
|
||||||
|
end
|
||||||
|
name led
|
||||||
|
from .o.a
|
||||||
|
to .out
|
||||||
|
program {EM}/lib.bin/em_led
|
||||||
|
mapflag -l* LNAME={PLATFORMDIR}/tail_*
|
||||||
|
mapflag -i SEPID=-b1:0
|
||||||
|
mapflag -fp FLOATS={EM}/{ILIB}fp
|
||||||
|
mapflag -ansi C_LIB={PLATFORMDIR}/tail_ac
|
||||||
|
args {ALIGN} {SEPID?} \
|
||||||
|
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
|
||||||
|
({RTS}:.ocm.b={PLATFORMDIR}/head_cc) \
|
||||||
|
({RTS}{ANSI?}:.c={PLATFORMDIR}/head_cc) \
|
||||||
|
({RTS}{ANSI?}:.cansi={PLATFORMDIR}/head_ac) \
|
||||||
|
({RTS}:.mod={PLATFORMDIR}/head_m2) \
|
||||||
|
({RTS}:.p={PLATFORMDIR}/head_pc) \
|
||||||
|
-o > < \
|
||||||
|
(.p:{TAIL}={PLATFORMDIR}/tail_pc) \
|
||||||
|
(.b:{TAIL}={PLATFORMDIR}/tail_bc) \
|
||||||
|
(.mod:{TAIL}={PLATFORMDIR}/tail_m2) \
|
||||||
|
(.ocm:{TAIL}={PLATFORMDIR}/tail_ocm) \
|
||||||
|
(.ocm.b:{TAIL}={OLD_C_LIB}) \
|
||||||
|
(.c:{TAIL}={C_LIB}) \
|
||||||
|
{FLOATS?} \
|
||||||
|
(.e:{TAIL}={PLATFORMDIR}/libsys.a \
|
||||||
|
{PLATFORMDIR}/tail_mon \
|
||||||
|
{PLATFORMDIR}/libsys.a \
|
||||||
|
{PLATFORMDIR}/libem.a \
|
||||||
|
{PLATFORMDIR}/libend.a)
|
||||||
|
linker
|
||||||
|
end
|
||||||
|
name cv
|
||||||
|
from .out
|
||||||
|
to .img
|
||||||
|
program {EM}/bin/aslod
|
||||||
|
args < >
|
||||||
|
outfile pc86.img
|
||||||
|
end
|
54
plat/pc86/libsys/_brk.s
Normal file
54
plat/pc86/libsys/_brk.s
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
! This file contains the code necessary to extend the ACK heap. This is called
|
||||||
|
! by a i86/libem helper function called .strhp, which takes care of updating
|
||||||
|
! some magic global variables --- defined here.
|
||||||
|
|
||||||
|
! Pointer to the current top of the heap.
|
||||||
|
|
||||||
|
.sect .data
|
||||||
|
.define .reghp
|
||||||
|
.reghp:
|
||||||
|
.data2 endbss
|
||||||
|
|
||||||
|
! Pointer to the current top of memory.
|
||||||
|
|
||||||
|
.sect .data
|
||||||
|
.define .limhp
|
||||||
|
.limhp:
|
||||||
|
.data2 endbss
|
||||||
|
|
||||||
|
! Claims more memory from the system, but does not actually change those
|
||||||
|
! global variables (.strhp does that). This does not use the C calling
|
||||||
|
! convention!
|
||||||
|
!
|
||||||
|
! Stack: ( desired_limhp : actual_limhp )
|
||||||
|
! Also returns: ax = -1 on failure
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.define BRK
|
||||||
|
BRK:
|
||||||
|
pop bx ! holds return address
|
||||||
|
pop ax ! holds desired limhp
|
||||||
|
|
||||||
|
cmp ax, sp ! compare sp with si
|
||||||
|
jae fail ! si too big? (Overlaps stack?)
|
||||||
|
cmp ax, endbss ! compare with bottom of heap
|
||||||
|
jb fail ! si too small? (Overlaps bss?)
|
||||||
|
|
||||||
|
return:
|
||||||
|
push ax ! success
|
||||||
|
jmp bx
|
||||||
|
|
||||||
|
fail:
|
||||||
|
mov ax, -1
|
||||||
|
jmp return
|
165
plat/pc86/libsys/_mon.s
Normal file
165
plat/pc86/libsys/_mon.s
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.define __sys_params_in
|
||||||
|
.comm __sys_params_in, 6
|
||||||
|
|
||||||
|
.define __sys_params_out
|
||||||
|
.comm __sys_params_out, 2
|
||||||
|
|
||||||
|
.comm opcode, 2
|
||||||
|
.comm returnto, 2
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
|
||||||
|
! Called on system call. This does *not* use the C calling convention:
|
||||||
|
! ax: syscall number
|
||||||
|
! stack: ( param3 param2 param1 - result )
|
||||||
|
|
||||||
|
.define .mon
|
||||||
|
.mon:
|
||||||
|
mov (opcode), ax
|
||||||
|
pop (returnto)
|
||||||
|
|
||||||
|
cmp ax, 1
|
||||||
|
je exit
|
||||||
|
cmp ax, 3
|
||||||
|
je read
|
||||||
|
cmp ax, 4
|
||||||
|
je write
|
||||||
|
cmp ax, 5
|
||||||
|
je open
|
||||||
|
cmp ax, 6
|
||||||
|
je nop_1 ! close
|
||||||
|
cmp ax, 20
|
||||||
|
je nop_0 ! getpid
|
||||||
|
cmp ax, 35
|
||||||
|
je nop_1 ! time
|
||||||
|
cmp ax, 48
|
||||||
|
je sigtrp
|
||||||
|
cmp ax, 54
|
||||||
|
je ioctl
|
||||||
|
|
||||||
|
! Syscall not supported --- write out an error message and halt.
|
||||||
|
|
||||||
|
unsupported:
|
||||||
|
mov si, msg
|
||||||
|
1:
|
||||||
|
lodsb
|
||||||
|
andb al, al
|
||||||
|
jz 2f
|
||||||
|
movb ah, 0xE ! service
|
||||||
|
mov bx, 0x0007 ! page 0, white
|
||||||
|
int 0x10
|
||||||
|
jmp 1b
|
||||||
|
2:
|
||||||
|
|
||||||
|
! Write out the syscall number.
|
||||||
|
|
||||||
|
mov dx, (opcode)
|
||||||
|
mov cx, 4 ! 4 hex digits
|
||||||
|
1:
|
||||||
|
rol dx, 1 ! rotate so that highest 4 bits are at the bottom
|
||||||
|
rol dx, 1
|
||||||
|
rol dx, 1
|
||||||
|
rol dx, 1
|
||||||
|
mov ax, 0xE0F ! ah = request, al = mask for nybble
|
||||||
|
andb al, dl
|
||||||
|
addb al, 0x90 ! convert al to ascii hex (four instructions)
|
||||||
|
daa
|
||||||
|
adcb al, 0x40
|
||||||
|
daa
|
||||||
|
int 0x10
|
||||||
|
loop 1b
|
||||||
|
|
||||||
|
! Exit.
|
||||||
|
|
||||||
|
jmp EXIT
|
||||||
|
|
||||||
|
.sect .rom
|
||||||
|
msg:
|
||||||
|
.asciz 'NOSYS'
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
exit:
|
||||||
|
jmp EXIT
|
||||||
|
|
||||||
|
read:
|
||||||
|
mov ax, __sys_read
|
||||||
|
jmp in_3_out_1
|
||||||
|
|
||||||
|
write:
|
||||||
|
mov ax, __sys_write
|
||||||
|
jmp in_3_out_1
|
||||||
|
|
||||||
|
open:
|
||||||
|
add sp, 2*2
|
||||||
|
jmp unimplemented
|
||||||
|
|
||||||
|
ioctl:
|
||||||
|
mov ax, __sys_ioctl
|
||||||
|
jmp in_3_out_0
|
||||||
|
|
||||||
|
sigtrp:
|
||||||
|
add sp, 4
|
||||||
|
jmp unimplemented
|
||||||
|
|
||||||
|
in_3_out_0:
|
||||||
|
pop (__sys_params_in+0)
|
||||||
|
pop (__sys_params_in+2)
|
||||||
|
pop (__sys_params_in+4)
|
||||||
|
call ax
|
||||||
|
jmp out_0
|
||||||
|
|
||||||
|
in_3_out_1:
|
||||||
|
pop (__sys_params_in+0)
|
||||||
|
pop (__sys_params_in+2)
|
||||||
|
pop (__sys_params_in+4)
|
||||||
|
call ax
|
||||||
|
jmp out_1
|
||||||
|
|
||||||
|
out_0:
|
||||||
|
or ax, ax
|
||||||
|
jnz failed
|
||||||
|
push ax
|
||||||
|
jmp return
|
||||||
|
|
||||||
|
out_1:
|
||||||
|
or ax, ax
|
||||||
|
jnz failed
|
||||||
|
push (__sys_params_out)
|
||||||
|
push ax
|
||||||
|
jmp return
|
||||||
|
|
||||||
|
unimplemented:
|
||||||
|
mov ax, EBADMON
|
||||||
|
failed:
|
||||||
|
push ax
|
||||||
|
push ax
|
||||||
|
jmp return
|
||||||
|
|
||||||
|
nop_1:
|
||||||
|
add sp, 1*2
|
||||||
|
jmp nop_0
|
||||||
|
nop_3:
|
||||||
|
add sp, 3*2
|
||||||
|
nop_0:
|
||||||
|
mov ax, 0
|
||||||
|
push ax
|
||||||
|
jmp return
|
||||||
|
|
||||||
|
return:
|
||||||
|
jmp (returnto)
|
||||||
|
|
87
plat/pc86/libsys/_sbrk.c
Normal file
87
plat/pc86/libsys/_sbrk.c
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
/* There should be a header for brk and sbrk, but there isn't. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
/* #include <unistd.h> */
|
||||||
|
|
||||||
|
extern char _end[];
|
||||||
|
static char* brkpointer = _end;
|
||||||
|
|
||||||
|
static void prints(char* s)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
char c = *s++;
|
||||||
|
if (!c)
|
||||||
|
break;
|
||||||
|
write(0, &c, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printc(unsigned int n)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
|
n &= 0xF;
|
||||||
|
if (n < 10)
|
||||||
|
c = n + '0';
|
||||||
|
else
|
||||||
|
c = n + 'A' - 10;
|
||||||
|
|
||||||
|
write(0, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printh(unsigned int n)
|
||||||
|
{
|
||||||
|
printc(n>>12);
|
||||||
|
printc(n>>8);
|
||||||
|
printc(n>>4);
|
||||||
|
printc(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waitforkey(void)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
read(1, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _brk(char* newend)
|
||||||
|
{
|
||||||
|
char dummy;
|
||||||
|
|
||||||
|
/* Ensure that newend is reasonable. */
|
||||||
|
|
||||||
|
if ((newend < _end) || (newend > (&dummy - 256)))
|
||||||
|
{
|
||||||
|
prints("[brk to ");
|
||||||
|
printh((unsigned int) newend);
|
||||||
|
prints(" failed]\n\r");
|
||||||
|
waitforkey();
|
||||||
|
errno = ENOMEM;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
prints("[brk to ");
|
||||||
|
printh((unsigned int) newend);
|
||||||
|
prints("]\n\r");
|
||||||
|
waitforkey();
|
||||||
|
brkpointer = newend;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* _sbrk(int delta)
|
||||||
|
{
|
||||||
|
char* oldpointer = brkpointer;
|
||||||
|
prints("[sbrk delta ");
|
||||||
|
printh((unsigned int) delta);
|
||||||
|
prints(" from ");
|
||||||
|
printh((unsigned int) oldpointer);
|
||||||
|
prints("]\n\r");
|
||||||
|
printh((unsigned int) brkpointer);
|
||||||
|
prints(" ");
|
||||||
|
printh((unsigned int) _end);
|
||||||
|
if (_brk(oldpointer + delta) == -1)
|
||||||
|
return (char*)-1;
|
||||||
|
|
||||||
|
return oldpointer;
|
||||||
|
}
|
52
plat/pc86/libsys/_sys_ioctl.c
Normal file
52
plat/pc86/libsys/_sys_ioctl.c
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sgtty.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
int _sys_ttyflags = ECHO;
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
int request;
|
||||||
|
void* argp;
|
||||||
|
} _sys_params_in;
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
} _sys_params_out;
|
||||||
|
|
||||||
|
#define P _sys_params_in
|
||||||
|
|
||||||
|
static int tiocgetp(void)
|
||||||
|
{
|
||||||
|
struct sgttyb* s = P.argp;
|
||||||
|
s->sg_flags = _sys_ttyflags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tiocsetp(void)
|
||||||
|
{
|
||||||
|
struct sgttyb* s = P.argp;
|
||||||
|
_sys_ttyflags = s->sg_flags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_ioctl(void)
|
||||||
|
{
|
||||||
|
switch (P.request)
|
||||||
|
{
|
||||||
|
case TIOCGETP:
|
||||||
|
_sys_params_out.result = tiocgetp();
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case TIOCSETP:
|
||||||
|
_sys_params_out.result = tiocsetp();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sys_params_out.result = -1;
|
||||||
|
errno = EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
22
plat/pc86/libsys/_sys_rawread.s
Normal file
22
plat/pc86/libsys/_sys_rawread.s
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
! Reads a single byte.
|
||||||
|
|
||||||
|
.define __sys_rawread
|
||||||
|
__sys_rawread:
|
||||||
|
xorb ah, ah
|
||||||
|
int 0x16
|
||||||
|
xorb ah, ah
|
||||||
|
ret
|
||||||
|
|
28
plat/pc86/libsys/_sys_rawwrite.s
Normal file
28
plat/pc86/libsys/_sys_rawwrite.s
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
|
||||||
|
! Writes a single byte to the console.
|
||||||
|
|
||||||
|
.define __sys_rawwrite
|
||||||
|
.extern __sys_rawwrite
|
||||||
|
|
||||||
|
__sys_rawwrite:
|
||||||
|
push bp
|
||||||
|
mov bp, sp
|
||||||
|
|
||||||
|
movb al, 4(bp)
|
||||||
|
movb ah, 0x0E
|
||||||
|
mov bx, 0x0007
|
||||||
|
int 0x10
|
||||||
|
jmp .cret
|
||||||
|
|
49
plat/pc86/libsys/_sys_read.c
Normal file
49
plat/pc86/libsys/_sys_read.c
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sgtty.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char* buffer;
|
||||||
|
size_t count;
|
||||||
|
} _sys_params_in;
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
size_t bytesread;
|
||||||
|
} _sys_params_out;
|
||||||
|
|
||||||
|
#define P _sys_params_in
|
||||||
|
|
||||||
|
int _sys_read(void)
|
||||||
|
{
|
||||||
|
char i;
|
||||||
|
|
||||||
|
/* We're only allowed to read from fd 0, 1 or 2. */
|
||||||
|
|
||||||
|
if ((P.fd < 0) || (P.fd > 2))
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
/* Empty buffer? */
|
||||||
|
|
||||||
|
if (P.count == 0)
|
||||||
|
{
|
||||||
|
_sys_params_out.bytesread = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read one byte. */
|
||||||
|
|
||||||
|
i = _sys_rawread();
|
||||||
|
if ((i == '\r') && !(_sys_ttyflags & RAW))
|
||||||
|
i = '\n';
|
||||||
|
if (_sys_ttyflags & ECHO)
|
||||||
|
_sys_write_tty(i);
|
||||||
|
|
||||||
|
*P.buffer = i;
|
||||||
|
|
||||||
|
_sys_params_out.bytesread = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
50
plat/pc86/libsys/_sys_write.c
Normal file
50
plat/pc86/libsys/_sys_write.c
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sgtty.h>
|
||||||
|
#include "libsys.h"
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
const char* buffer;
|
||||||
|
size_t count;
|
||||||
|
} _sys_params_in;
|
||||||
|
|
||||||
|
extern struct
|
||||||
|
{
|
||||||
|
size_t byteswritten;
|
||||||
|
} _sys_params_out;
|
||||||
|
|
||||||
|
#define P _sys_params_in
|
||||||
|
|
||||||
|
void _sys_write_tty(char c)
|
||||||
|
{
|
||||||
|
_sys_rawwrite(c);
|
||||||
|
if ((c == '\n') && !(_sys_ttyflags & RAW))
|
||||||
|
_sys_rawwrite('\r');
|
||||||
|
}
|
||||||
|
|
||||||
|
int _sys_write(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* We're only allowed to write to fd 0, 1 or 2. */
|
||||||
|
|
||||||
|
if ((P.fd < 0) || (P.fd > 2))
|
||||||
|
return EBADF;
|
||||||
|
|
||||||
|
/* Write all data. */
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
while (i < P.count)
|
||||||
|
{
|
||||||
|
_sys_write_tty(*P.buffer++);
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No failures. */
|
||||||
|
|
||||||
|
_sys_params_out.byteswritten = P.count;
|
||||||
|
return 0;
|
||||||
|
}
|
24
plat/pc86/libsys/errno.s
Normal file
24
plat/pc86/libsys/errno.s
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#
|
||||||
|
! $Source$
|
||||||
|
! $State$
|
||||||
|
|
||||||
|
! Declare segments (the order is important).
|
||||||
|
|
||||||
|
.sect .text
|
||||||
|
.sect .rom
|
||||||
|
.sect .data
|
||||||
|
.sect .bss
|
||||||
|
|
||||||
|
#define D(e) .define e; e
|
||||||
|
|
||||||
|
.sect .data
|
||||||
|
|
||||||
|
D(ERANGE) = 1
|
||||||
|
D(ESET) = 2
|
||||||
|
D(EIDIVZ) = 6
|
||||||
|
D(EHEAP) = 17
|
||||||
|
D(EILLINS) = 18
|
||||||
|
D(EODDZ) = 19
|
||||||
|
D(ECASE) = 20
|
||||||
|
D(EBADMON) = 25
|
||||||
|
|
11
plat/pc86/libsys/libsys.h
Normal file
11
plat/pc86/libsys/libsys.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef LIBSYS_H
|
||||||
|
#define LIBSYS_H
|
||||||
|
|
||||||
|
extern void _sys_rawwrite(unsigned char b);
|
||||||
|
extern unsigned char _sys_rawread(void);
|
||||||
|
|
||||||
|
extern void _sys_write_tty(char c);
|
||||||
|
|
||||||
|
extern int _sys_ttyflags;
|
||||||
|
|
||||||
|
#endif
|
20
plat/pc86/libsys/pmfile
Normal file
20
plat/pc86/libsys/pmfile
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
-- $Source$
|
||||||
|
-- $State$
|
||||||
|
|
||||||
|
local d = ROOTDIR.."plat/pc86/libsys/"
|
||||||
|
|
||||||
|
libsys_pc86 = acklibrary {
|
||||||
|
ACKBUILDFLAGS = {PARENT, "-ansi"},
|
||||||
|
ACKINCLUDES = {"%BINDIR%include"},
|
||||||
|
|
||||||
|
ackfile (d.."errno.s"),
|
||||||
|
ackfile (d.."_mon.s"),
|
||||||
|
ackfile (d.."_brk.s"),
|
||||||
|
ackfile (d.."_sys_rawread.s"),
|
||||||
|
ackfile (d.."_sys_rawwrite.s"),
|
||||||
|
ackfile (d.."_sys_read.c"),
|
||||||
|
ackfile (d.."_sys_write.c"),
|
||||||
|
ackfile (d.."_sys_ioctl.c"),
|
||||||
|
|
||||||
|
install = pm.install("%BINDIR%lib/%PLATFORM%/libsys.a"),
|
||||||
|
}
|
37
plat/pc86/pmfile
Normal file
37
plat/pc86/pmfile
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
-- $Source$
|
||||||
|
-- $State$
|
||||||
|
|
||||||
|
local d = ROOTDIR.."plat/pc86/"
|
||||||
|
|
||||||
|
include (d.."libsys/pmfile")
|
||||||
|
|
||||||
|
local bootsector = ackfile {
|
||||||
|
file (d.."boot.s"),
|
||||||
|
install = pm.install("%BINDIR%lib/pc86/boot.o"),
|
||||||
|
}
|
||||||
|
|
||||||
|
local descr = group {
|
||||||
|
install = pm.install(d.."descr", "%BINDIR%%PLATIND%/%PLATFORM%/descr")
|
||||||
|
}
|
||||||
|
|
||||||
|
platform_pc86 = group {
|
||||||
|
ARCH = "i86",
|
||||||
|
PLATFORM = "pc86",
|
||||||
|
OPTIMISATION = "-O",
|
||||||
|
|
||||||
|
-- Ensure the descr file is installed first because we'll need it
|
||||||
|
-- to build the libraries.
|
||||||
|
|
||||||
|
descr,
|
||||||
|
|
||||||
|
-- Build the back-end support.
|
||||||
|
|
||||||
|
mach_i86,
|
||||||
|
support_i86,
|
||||||
|
lang_runtimes,
|
||||||
|
|
||||||
|
-- Build the PC standalone syscall library.
|
||||||
|
|
||||||
|
libsys_pc86,
|
||||||
|
bootsector,
|
||||||
|
}
|
Loading…
Reference in a new issue