Added 8086 PC bootable floppy support (pc86).
authordtrg <none@none>
Tue, 20 Feb 2007 00:25:12 +0000 (00:25 +0000)
committerdtrg <none@none>
Tue, 20 Feb 2007 00:25:12 +0000 (00:25 +0000)
15 files changed:
plat/pc86/README [new file with mode: 0644]
plat/pc86/boot.s [new file with mode: 0644]
plat/pc86/descr [new file with mode: 0644]
plat/pc86/libsys/_brk.s [new file with mode: 0644]
plat/pc86/libsys/_mon.s [new file with mode: 0644]
plat/pc86/libsys/_sbrk.c [new file with mode: 0644]
plat/pc86/libsys/_sys_ioctl.c [new file with mode: 0644]
plat/pc86/libsys/_sys_rawread.s [new file with mode: 0644]
plat/pc86/libsys/_sys_rawwrite.s [new file with mode: 0644]
plat/pc86/libsys/_sys_read.c [new file with mode: 0644]
plat/pc86/libsys/_sys_write.c [new file with mode: 0644]
plat/pc86/libsys/errno.s [new file with mode: 0644]
plat/pc86/libsys/libsys.h [new file with mode: 0644]
plat/pc86/libsys/pmfile [new file with mode: 0644]
plat/pc86/pmfile [new file with mode: 0644]

diff --git a/plat/pc86/README b/plat/pc86/README
new file mode 100644 (file)
index 0000000..b4a02db
--- /dev/null
@@ -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
diff --git a/plat/pc86/boot.s b/plat/pc86/boot.s
new file mode 100644 (file)
index 0000000..61713f2
--- /dev/null
@@ -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:
diff --git a/plat/pc86/descr b/plat/pc86/descr
new file mode 100644 (file)
index 0000000..1b6e728
--- /dev/null
@@ -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
diff --git a/plat/pc86/libsys/_brk.s b/plat/pc86/libsys/_brk.s
new file mode 100644 (file)
index 0000000..dffc06e
--- /dev/null
@@ -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
diff --git a/plat/pc86/libsys/_mon.s b/plat/pc86/libsys/_mon.s
new file mode 100644 (file)
index 0000000..e998f92
--- /dev/null
@@ -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)
+       
\ No newline at end of file
diff --git a/plat/pc86/libsys/_sbrk.c b/plat/pc86/libsys/_sbrk.c
new file mode 100644 (file)
index 0000000..f189626
--- /dev/null
@@ -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;
+}
diff --git a/plat/pc86/libsys/_sys_ioctl.c b/plat/pc86/libsys/_sys_ioctl.c
new file mode 100644 (file)
index 0000000..c35e3c2
--- /dev/null
@@ -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;
+}
diff --git a/plat/pc86/libsys/_sys_rawread.s b/plat/pc86/libsys/_sys_rawread.s
new file mode 100644 (file)
index 0000000..bf933b4
--- /dev/null
@@ -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
+       
\ No newline at end of file
diff --git a/plat/pc86/libsys/_sys_rawwrite.s b/plat/pc86/libsys/_sys_rawwrite.s
new file mode 100644 (file)
index 0000000..1193ed8
--- /dev/null
@@ -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
+       
\ No newline at end of file
diff --git a/plat/pc86/libsys/_sys_read.c b/plat/pc86/libsys/_sys_read.c
new file mode 100644 (file)
index 0000000..cc1a1e5
--- /dev/null
@@ -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;
+}
diff --git a/plat/pc86/libsys/_sys_write.c b/plat/pc86/libsys/_sys_write.c
new file mode 100644 (file)
index 0000000..da64d46
--- /dev/null
@@ -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;
+}
diff --git a/plat/pc86/libsys/errno.s b/plat/pc86/libsys/errno.s
new file mode 100644 (file)
index 0000000..8392154
--- /dev/null
@@ -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
+
diff --git a/plat/pc86/libsys/libsys.h b/plat/pc86/libsys/libsys.h
new file mode 100644 (file)
index 0000000..75ccf5c
--- /dev/null
@@ -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
diff --git a/plat/pc86/libsys/pmfile b/plat/pc86/libsys/pmfile
new file mode 100644 (file)
index 0000000..456d4b1
--- /dev/null
@@ -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"),
+}
diff --git a/plat/pc86/pmfile b/plat/pc86/pmfile
new file mode 100644 (file)
index 0000000..4ff0e88
--- /dev/null
@@ -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,
+}