Add the very experimental qemuppc plat, intended to generate minimal images

which can be emulated using qemu (for, hopefully, a test suite). Currently it
generates images which won't run because there's no RAM.
This commit is contained in:
David Given 2016-11-12 19:20:58 +01:00
parent 852d3a691d
commit 48e74f46fc
29 changed files with 946 additions and 2 deletions

View file

@ -9,6 +9,7 @@ vars.plats = {
"linux386",
"linux68k",
"linuxppc",
"qemuppc",
"pc86",
"rpi",
}

View file

@ -33,8 +33,7 @@ var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
name be
from .m.g
to .s
# Change this back to ncg to revert to the old code generator
program {EM}/lib/ack/{PLATFORM}/mcg
program {EM}/lib/ack/{PLATFORM}/ncg
mapflag -gdb GF=-gdb
args {GF?} <
stdout

42
plat/qemuppc/README Normal file
View file

@ -0,0 +1,42 @@
# $Source: /cvsroot/tack/Ack/plat/linux386/README,v $
# $State: Exp $
# $Revision: 1.2 $
The linux386 platform
=====================
linux386 is an i386-based BSP that produces Linux ELF executables.
This port only implements a very limited number of system calls; basically,
just enough to make the demo apps run. Adding more is easy, but there are some
subtleties that require more thought. The port should be considered only in
proof-of-concept stage right now.
Important note: you *can't* link access ELF shared libraries from these
executables. In other words, you have to all your work from inside ACK.
IEEE floating point is available, but requires an FPU.
The executables are generated with aelfslod and are extremely simple; there's
one rwx ELF section which contains all the application's code and data. This
is not optimal, but it does work.
Bugs
====
isatty() is a stub and always returns 0.
Example command line
====================
ack -mlinux386 -O -o linux386.exe examples/paranoia.c
The file linux386.exe can then be run on a i386 Linux machine (or on an
emulation thereof).
David Given
dg@cowlark.com

74
plat/qemuppc/boot.s Normal file
View file

@ -0,0 +1,74 @@
#
! $Source: /cvsroot/tack/Ack/plat/linux386/boot.s,v $
! $State: Exp $
! $Revision: 1.3 $
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
begtext:
! This code is placed at the beginning of the ELF executable and is the
! first thing that runs.
!
! On entry, the stack looks like this:
!
! sp+... NULL
! sp+8+(4*argc) env (X quads)
! sp+4+(4*argc) NULL
! sp+4 argv (argc quads)
! sp argc
!
! The ACK actually expects:
!
! sp+8 argc
! sp+4 ptr to argv
! sp ptr to env
li32 r3, envp
stwu r3, -4(sp)
li32 r3, argv
stwu r3, -4(sp)
li32 r3, 1 ! argc
stwu r3, -4(sp)
bl __m_a_i_n
! falls through
.define __exit
.extern __exit
.define EXIT
.extern EXIT
__exit:
EXIT:
b EXIT
! 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:
! Some magic data. All EM systems need these.
.define _errno
.comm _errno, 4 ! Posix errno storage
! The argv and env arrays.
.sect .rom
argv: .data4 exename, 0
envp: .data4 0
exename: .asciz 'qemuppc.img'
.define .trppc, .ignmask
.comm .trppc, 4 ! ptr to user trap handler
.comm .ignmask, 4 ! user trap ignore mask

View file

@ -0,0 +1,25 @@
include("plat/build.lua")
ackfile {
name = "boot",
srcs = { "./boot.s" },
vars = { plat = "qemuppc" }
}
build_plat_libs {
name = "libs",
arch = "powerpc",
plat = "qemuppc",
}
installable {
name = "pkg",
map = {
"+tools",
"+libs",
"./include+pkg",
["$(PLATIND)/qemuppc/boot.o"] = "+boot",
["$(PLATIND)/qemuppc/libsys.a"] = "./libsys+lib",
}
}

View file

@ -0,0 +1,33 @@
include("plat/build.lua")
build_as {
name = "as",
arch = "powerpc",
}
build_mcg {
name = "mcg",
arch = "powerpc",
}
build_ncg {
name = "ncg",
arch = "powerpc",
}
build_top {
name = "top",
arch = "powerpc",
}
return installable {
name = "tools",
map = {
["$(PLATDEP)/qemuppc/as"] = "+as",
["$(PLATDEP)/qemuppc/ncg"] = "+ncg",
["$(PLATDEP)/qemuppc/mcg"] = "+mcg",
["$(PLATDEP)/qemuppc/top"] = "+top",
["$(PLATIND)/descr/qemuppc"] = "./descr",
"util/opt+pkg",
}
}

89
plat/qemuppc/descr Normal file
View file

@ -0,0 +1,89 @@
# plat/linuxppc/descr
var w=4
var wa=4
var p={w}
var pa={w}
var s=2
var sa={s}
var l={w}
var la={w}
var f={w}
var fa={w}
var d=8
var da={d}
var x=8
var xa={x}
var ARCH=powerpc
var PLATFORM=qemuppc
var PLATFORMDIR={EM}/share/ack/{PLATFORM}
var CPP_F=-D__unix
var ALIGN=-a0:4 -a1:4 -a2:4 -a3:4 -b0:0x01000000
var C_LIB={PLATFORMDIR}/libc-ansi.a
# bitfields reversed for compatibility with (g)cc.
var CC_ALIGN=-Vr
var OLD_C_LIB={C_LIB}
var MACHOPT_F=
# Override the setting in fe so that files compiled for qemuppc can see
# the platform-specific headers.
var C_INCLUDES=-I{PLATFORMDIR}/include -I{EM}/share/ack/include/ansi
name be
from .m.g
to .s
# Change this back to ncg to revert to the old code generator
program {EM}/lib/ack/{PLATFORM}/ncg
mapflag -gdb GF=-gdb
args {GF?} <
stdout
need .e
end
name asopt
from .s
to .so
program {EM}/lib/ack/{PLATFORM}/top
args
optimizer
stdin
stdout
end
name as
from .s.so
to .o
program {EM}/lib/ack/{PLATFORM}/as
args - -o > <
prep cond
end
name led
from .o.a
to .out
program {EM}/lib/ack/em_led
mapflag -l* LNAME={PLATFORMDIR}/lib*
mapflag -fp FLOATS={EM}/{LIB}fp
args {ALIGN} {SEPID?} \
(.e:{HEAD}={PLATFORMDIR}/boot.o) \
({RTS}:.ocm.b={PLATFORMDIR}/c-ansi.o) \
({RTS}:.c={PLATFORMDIR}/c-ansi.o) \
({RTS}:.mod={PLATFORMDIR}/modula2.o) \
({RTS}:.p={PLATFORMDIR}/pascal.o) \
-o > < \
(.p:{TAIL}={PLATFORMDIR}/libpascal.a) \
(.b:{TAIL}={PLATFORMDIR}/libbasic.a) \
(.mod:{TAIL}={PLATFORMDIR}/libmodula2.a) \
(.ocm:{TAIL}={PLATFORMDIR}/liboccam.a) \
(.ocm.b.mod.c.p:{TAIL}={PLATFORMDIR}/libc.a) \
{FLOATS?} \
(.e:{TAIL}={PLATFORMDIR}/libem.a \
{PLATFORMDIR}/libsys.a \
{PLATFORMDIR}/libend.a)
linker
end
name cv
from .out
to .exe
program {EM}/bin/aslod
args < >
outfile qemuppc.img
end

View file

@ -0,0 +1,14 @@
/* $Source: /cvsroot/tack/Ack/plat/linux386/include/ack/config.h,v $
* $State: Exp $
* $Revision: 1.1 $
*/
#ifndef _ACK_CONFIG_H
#define _ACK_CONFIG_H
/* We're providing a time() system call rather than wanting a wrapper around
* gettimeofday() in the libc. */
#define ACKCONF_TIME_IS_A_SYSCALL
#endif

View file

@ -0,0 +1,24 @@
include("plat/build.lua")
headermap = {}
packagemap = {}
local function addheader(h)
headermap[h] = "./"..h
packagemap["$(PLATIND)/qemuppc/include/"..h] = "./"..h
end
addheader("ack/config.h")
addheader("sys/ioctl.h")
addheader("unistd.h")
acklibrary {
name = "headers",
hdrs = headermap
}
installable {
name = "pkg",
map = packagemap
}

View file

@ -0,0 +1,76 @@
/* $Source: /cvsroot/tack/Ack/plat/linux386/include/sys/ioctl.h,v $
* $State: Exp $
* $Revision: 1.1 $
*/
#ifndef _SYS_IOCTL_H
#define _SYS_IOCTL_H
/* These are copied from the ioctl_list(2) man page. */
/* <include/asm-i386/socket.h> */
#define FIOSETOWN 0x00008901
#define SIOCSPGRP 0x00008902
#define FIOGETOWN 0x00008903
#define SIOCGPGRP 0x00008904
#define SIOCATMARK 0x00008905
#define SIOCGSTAMP 0x00008906
/* <include/asm-i386/termios.h> */
#define TCGETS 0x00005401
#define TCSETS 0x00005402
#define TCSETSW 0x00005403
#define TCSETSF 0x00005404
#define TCGETA 0x00005405
#define TCSETA 0x00005406
#define TCSETAW 0x00005407
#define TCSETAF 0x00005408
#define TCSBRK 0x00005409
#define TCXONC 0x0000540A
#define TCFLSH 0x0000540B
#define TIOCEXCL 0x0000540C
#define TIOCNXCL 0x0000540D
#define TIOCSCTTY 0x0000540E
#define TIOCGPGRP 0x0000540F
#define TIOCSPGRP 0x00005410
#define TIOCOUTQ 0x00005411
#define TIOCSTI 0x00005412
#define TIOCGWINSZ 0x00005413
#define TIOCSWINSZ 0x00005414
#define TIOCMGET 0x00005415
#define TIOCMBIS 0x00005416
#define TIOCMBIC 0x00005417
#define TIOCMSET 0x00005418
#define TIOCGSOFTCAR 0x00005419
#define TIOCSSOFTCAR 0x0000541A
#define FIONREAD 0x0000541B
#define TIOCINQ 0x0000541B
#define TIOCLINUX 0x0000541C
#define TIOCCONS 0x0000541D
#define TIOCGSERIAL 0x0000541E
#define TIOCSSERIAL 0x0000541F
#define TIOCPKT 0x00005420
#define FIONBIO 0x00005421
#define TIOCNOTTY 0x00005422
#define TIOCSETD 0x00005423
#define TIOCGETD 0x00005424
#define TCSBRKP 0x00005425
#define TIOCTTYGSTRUCT 0x00005426
#define FIONCLEX 0x00005450
#define FIOCLEX 0x00005451
#define FIOASYNC 0x00005452
#define TIOCSERCONFIG 0x00005453
#define TIOCSERGWILD 0x00005454
#define TIOCSERSWILD 0x00005455
#define TIOCGLCKTRMIOS 0x00005456
#define TIOCSLCKTRMIOS 0x00005457
#define TIOCSERGSTRUCT 0x00005458
#define TIOCSERGETLSR 0x00005459
#define TIOCSERGETMULTI 0x0000545A
#define TIOCSERSETMULTI 0x0000545B
#endif

View file

@ -0,0 +1,123 @@
/*
* unistd.h - standard system calls
*/
/* $Id$ */
#ifndef _UNISTD_H
#define _UNISTD_H
#include <stddef.h>
#include <time.h>
/* Types */
typedef int pid_t;
typedef int mode_t;
typedef long suseconds_t;
/* Time handling. */
struct timeval
{
time_t tv_sec;
suseconds_t tv_usec;
};
struct timezone
{
int tz_minuteswest;
int tz_dsttime;
}; /* obsolete, unused */
extern int gettimeofday(struct timeval* tv, struct timezone* tz);
extern int settimeofday(const struct timeval* tv, const struct timezone* tz);
/* File access. */
enum
{
O_ACCMODE = 0x3,
O_RDONLY = 0,
O_WRONLY = 1,
O_RDWR = 2,
O_CREAT = 0x10,
O_TRUNC = 0x20,
O_APPEND = 0x40
};
extern int open(const char* path, int access, ...);
extern int creat(const char* path, mode_t mode);
extern int close(int d);
extern int read(int fd, void* buffer, size_t count);
extern int write(int fd, void* buffer, size_t count);
extern off_t lseek(int fildes, off_t offset, int whence);
extern int fcntl(int fd, int op, ...);
/* Special variables */
extern char** environ;
/* Implemented system calls */
extern void _exit(int);
extern pid_t getpid(void);
extern int brk(void* ptr);
extern void* sbrk(intptr_t increment);
extern int isatty(int d);
/* Signal handling */
typedef int sig_atomic_t;
#define SIG_ERR ((sighandler_t) -1) /* Error return. */
#define SIG_DFL ((sighandler_t) 0) /* Default action. */
#define SIG_IGN ((sighandler_t) 1) /* Ignore signal. */
#define SIGHUP 1 /* Hangup (POSIX). */
#define SIGINT 2 /* Interrupt (ANSI). */
#define SIGQUIT 3 /* Quit (POSIX). */
#define SIGILL 4 /* Illegal instruction (ANSI). */
#define SIGTRAP 5 /* Trace trap (POSIX). */
#define SIGABRT 6 /* Abort (ANSI). */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). */
#define SIGFPE 8 /* Floating-point exception (ANSI). */
#define SIGKILL 9 /* Kill, unblockable (POSIX). */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX). */
#define SIGSEGV 11 /* Segmentation violation (ANSI). */
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). */
#define SIGPIPE 13 /* Broken pipe (POSIX). */
#define SIGALRM 14 /* Alarm clock (POSIX). */
#define SIGTERM 15 /* Termination (ANSI). */
#define SIGSTKFLT 16 /* Stack fault. */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
#define SIGCHLD 17 /* Child status has changed (POSIX). */
#define SIGCONT 18 /* Continue (POSIX). */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). */
#define SIGTSTP 20 /* Keyboard stop (POSIX). */
#define SIGTTIN 21 /* Background read from tty (POSIX). */
#define SIGTTOU 22 /* Background write to tty (POSIX). */
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V). */
#define SIGSYS 31 /* Bad system call. */
#define SIGUNUSED 31
#define _NSIG 32 /* Biggest signal number + 1
(not including real-time signals). */
typedef void (*sighandler_t)(int);
extern sighandler_t signal(int signum, sighandler_t handler);
extern int raise(int signum);
#endif

View file

@ -0,0 +1,20 @@
#
! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_hol0.s,v $
! $State: Exp $
! $Revision: 1.1 $
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
!
! This data block is used to store information about the current line number
! and file.
.define hol0
.comm hol0, 8

View file

@ -0,0 +1,19 @@
#
#include "powerpc.h"
! 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:
li32 r3, 0
bclr ALWAYS, 0, 0

View file

@ -0,0 +1,20 @@
#
#include "powerpc.h"
! 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:
bclr ALWAYS, 0, 0

43
plat/qemuppc/libsys/brk.c Normal file
View file

@ -0,0 +1,43 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#define OUT_OF_MEMORY (void*)(-1) /* sbrk returns this on failure */
#define STACK_BUFFER 128 /* number of bytes to leave for stack */
extern char _end[1];
static char* current = _end;
int brk(void* newend)
{
/* This variable is used to figure out the current stack pointer,
* by taking its address. */
char dummy;
char* p = newend;
if ((p > (&dummy - STACK_BUFFER)) ||
(p < _end))
return -1;
current = p;
return 0;
}
void* sbrk(intptr_t increment)
{
char* old;
if (increment == 0)
return current;
old = current;
if (brk(old + increment) < 0)
return OUT_OF_MEMORY;
return old;
}

View file

@ -0,0 +1,16 @@
acklibrary {
name = "lib",
srcs = {
"./*.s",
"./*.c",
},
deps = {
"lang/cem/libcc.ansi/headers+headers",
"plat/qemuppc/include+headers",
"mach/powerpc/libem+headers_qemuppc",
},
vars = {
plat = "qemuppc"
}
}

View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int close(int fd)
{
errno = EBADF;
return -1;
}

View file

@ -0,0 +1,15 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int open(const char* path, int access, ...)
{
errno = EACCES;
return -1;
}

View file

@ -0,0 +1,13 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
pid_t getpid(void)
{
return 0;
}

View file

@ -0,0 +1,8 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int isatty(int fd)
{
return 1;
}

View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
int kill(pid_t pid, int sig)
{
errno = EINVAL;
return -1;
}

View 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

View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence)
{
errno = EINVAL;
return -1;
}

View file

@ -0,0 +1,14 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int creat(const char* path, int mode)
{
return open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
}

View file

@ -0,0 +1,38 @@
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
int read(int fd, void* buffer, size_t count)
{
char i;
/* We're only allowed to read from fd 0, 1 or 2. */
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Empty buffer? */
if (count == 0)
return 0;
/* Read one byte. */
i = _sys_rawread();
#if 0
if ((i == '\r') && !(_sys_ttyflags & RAW))
i = '\n';
if (_sys_ttyflags & ECHO)
_sys_write_tty(i);
#endif
if (i == '\r')
i = '\n';
_sys_write_tty(i);
*(char*)buffer = i;
return 1;
}

View file

@ -0,0 +1,15 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include "libsys.h"
sighandler_t signal(int signum, sighandler_t handler)
{
return SIG_DFL;
}

View file

@ -0,0 +1,17 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include "libsys.h"
time_t time(time_t* t)
{
if (t)
*t = 0;
return 0;
}

105
plat/qemuppc/libsys/trap.s Normal file
View file

@ -0,0 +1,105 @@
#
! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $
! $State: Exp $
! $Revision: 1.1 $
! Declare segments (the order is important).
.sect .text
.sect .rom
.sect .data
.sect .bss
.sect .text
#define IFFALSE 4
#define IFTRUE 12
#define ALWAYS 20
#define LT 0
#define GT 1
#define EQ 2
#define OV 3
EARRAY = 0
ERANGE = 1
ESET = 2
EIOVFL = 3
EFOVFL = 4
EFUNFL = 5
EIDIVZ = 6
EFDIVZ = 7
EIUND = 8
EFUND = 9
ECONV = 10
ESTACK = 16
EHEAP = 17
EILLINS = 18
EODDZ = 19
ECASE = 20
EMEMFLT = 21
EBADPTR = 22
EBADPC = 23
EBADLAE = 24
EBADMON = 25
EBADLIN = 26
EBADGTO = 27
EUNIMPL = 63 ! unimplemented em-instruction called
! EM trap handling.
.define .trap_ecase
.trap_ecase:
addi r3, r0, ECASE
b .trap
.define .trap_earray
.trap_earray:
addi r3, r0, EARRAY
b .trap
.define .trap
.trap:
cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored
bc IFTRUE, LT, 1f
addi r4, r0, 1
rlwnm r4, r4, r3, 0, 31 ! calculate trap bit
li32 r5, .ignmask
lwz r5, 0(r5) ! load ignore mask
and. r4, r4, r5 ! compare
bclr IFFALSE, EQ, 0 ! return if non-zero
1:
li32 r4, .trppc
lwz r5, 0(r4) ! load user trap routine
or. r5, r5, r5 ! test
bc IFTRUE, EQ, fatal ! if no user trap routine, bail out
addi r0, r0, 0
stw r0, 0(r4) ! reset trap routine
mfspr r0, lr
stwu r0, -4(sp) ! save old lr
stwu r3, -4(sp)
mtspr ctr, r5
bcctrl ALWAYS, 0, 0 ! call trap routine
lwz r0, 4(sp) ! load old lr again
addi sp, sp, 8 ! retract over stack usage
bclr ALWAYS, 0, 0 ! return
fatal:
addi r3, r0, 1
li32 r4, message
addi r5, r0, 6
addi r0, r0, 4 ! write()
sc 0
addi r0, r0, 1 ! exit()
sc 0
.sect .rom
message:
.ascii "TRAP!\n"

View file

@ -0,0 +1,48 @@
/* $Source$
* $State$
* $Revision$
*/
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include "libsys.h"
void _sys_write_tty(char c)
{
_sys_rawwrite(c);
#if 0
if ((c == '\n') && !(_sys_ttyflags & RAW))
_sys_rawwrite('\r');
#endif
if (c == '\n')
_sys_rawwrite('\r');
}
int write(int fd, void* buffer, size_t count)
{
int i;
char* p = buffer;
/* We're only allowed to write to fd 0, 1 or 2. */
if ((fd < 0) || (fd > 2))
{
errno = EBADF;
return -1;
}
/* Write all data. */
i = 0;
while (i < count)
{
_sys_write_tty(*p++);
i++;
}
/* No failures. */
return count;
}