Compare commits

..

12 Commits

15 changed files with 398 additions and 229 deletions

View File

@@ -11,13 +11,13 @@ dev: dev-image ## Launch a dev container
.PHONY: binaries .PHONY: binaries
binaries: ## Build all small binaries binaries: ## Build all small binaries
docker build --build-arg TARGET=call.bin -o . --target=export .
docker build --build-arg TARGET=readfloppy.bin -o . --target=export . docker build --build-arg TARGET=readfloppy.bin -o . --target=export .
docker build --build-arg TARGET=writefloppy.bin -o . --target=export . docker build --build-arg TARGET=writefloppy.bin -o . --target=export .
docker build --build-arg TARGET=copy.bin -o . --target=export .
docker build --build-arg TARGET=format.bin -o . --target=export .
docker build --build-arg TARGET=crc16.bin -o . --target=export . docker build --build-arg TARGET=crc16.bin -o . --target=export .
docker build --build-arg TARGET=hello.bin -o . --target=export . docker build --build-arg TARGET=hello.bin -o . --target=export .
docker build --build-arg TARGET=copy.bin -o . --target=export .
docker build --build-arg TARGET=call.bin -o . --target=export .
docker build --build-arg TARGET=format.bin -o . --target=export .
docker build --build-arg TARGET=readio.bin -o . --target=export . docker build --build-arg TARGET=readio.bin -o . --target=export .
docker build --build-arg TARGET=writeio.bin -o . --target=export . docker build --build-arg TARGET=writeio.bin -o . --target=export .

View File

@@ -18,17 +18,17 @@ LDFLAGS = -mregparmcall -Wl,--gc-sections -Os -nostdlib -flto
fat12boot.bin: fat12boot.bin:
$(OBJCOPY) -O binary $< $@ $(OBJCOPY) -O binary $< $@
fat12boot.elf: fat12boot.o fat12.o bootsect.S fat12boot.elf: fat12boot.o fat12.o bootsect.S stdlib.o
fat12boot.elf: LDFLAGS += -T bootsect.ld fat12boot.elf: LDFLAGS += -T bootsect.ld
fat12boot.bin: fat12boot.elf fat12boot.bin: fat12boot.elf
stdlib.o: CFLAGS := $(filter-out -flto, $(CFLAGS)) stdlib.o: CFLAGS := $(filter-out -flto, $(CFLAGS))
polmon.elf: LDFLAGS += -T flat1000.ld polmon.elf: LDFLAGS += -T init.ld
polmon.elf: polmon.o stdlib.o polmon.elf: polmon.o stdlib.o
polio.elf: LDFLAGS += -T flat0600.ld polio.elf: LDFLAGS += -T flat0600.ld -mprotected-mode
polio.elf: polio-main.o polio.s fat12.o paracomm.o stdlib.o polio.elf: polio-main.o polio.s fat12.o paracomm.o stdlib.o
paracli.elf: LDFLAGS += -T doscom.ld paracli.elf: LDFLAGS += -T doscom.ld

View File

@@ -5,7 +5,7 @@
.global _start .global _start
_start: _start:
#ifndef NOBPB #ifndef NOBPB
jmp l0 jmp 0f
nop nop
.ascii "IBM 3.1" .ascii "IBM 3.1"
@@ -18,7 +18,7 @@ bpb_localsectors: .word 720
bpb_mediadescr: .byte 0xfd bpb_mediadescr: .byte 0xfd
bpb_sectsperfat: .word 2 bpb_sectsperfat: .word 2
l0: 0:
#endif // NOBPB #endif // NOBPB
cli cli
xor %ax, %ax xor %ax, %ax

View File

@@ -19,15 +19,15 @@ _start:
mov bx, 0x6 mov bx, 0x6
xor cx, cx xor cx, cx
a1: a1:
cmp cx, [es:si+4] cmp cx, [si+4]
jge a2 jge a2
lea ax, [es:si+bx] lea ax, [si+bx]
push ax push ax
add bl, 2 add bl, 2
inc cl inc cl
jmp a1 jmp a1
a2: a2:
call far [es:si] call far [si]
pop bp pop bp
pop di pop di
pop si pop si

45
src/crc16.asm Normal file
View File

@@ -0,0 +1,45 @@
CPU 8086
_start:
push bp
mov bp, sp
mov si, [bp+8]
push word [si]
mov si, [bp+10]
push word [si]
call crc16
mov di, [bp+6]
mov [di], ax
mov sp, bp
pop bp
retf 6
crc16:
push bp
mov bp, sp
mov bx, [bp+4]
add [bp+6], bx
mov ax, -1
.L2:
cmp bx, [bp+6]
jne .L5
pop bp
ret
.L5:
mov dl, [bx]
mov cl, 0x8
shl dx, cl
xor ax, dx
mov dl, cl
.L4:
mov cx, ax
shl cx, 1
test ax, ax
xchg cx, ax
jge .L3
xor ax, 4129
.L3:
dec dl
jne .L4
inc bx
jmp .L2

View File

@@ -1,57 +0,0 @@
.arch i8086,jumps
.code16
.att_syntax prefix
#NO_APP
#APP
.section .text.init
.global _start
_start:
.section .text.main
.global main
main:
push %bp
mov %sp, %bp
mov 8(%bp), %si
push (%si)
call crc16
add $0x2, %sp
mov 6(%bp), %di
mov %ax, (%di)
pop %bp
lret $4
#NO_APP
.text
.global crc16
.type crc16, @function
crc16:
pushw %bp
movw %sp, %bp
xorw %bx, %bx
movw $-1, %ax
.L2:
cmpw 4(%bp), %bx
jne .L5
popw %bp
ret
.L5:
movb %cs:(%bx), %dl
movb $8, %cl
shlw %cl, %dx
xorw %dx, %ax
movb %cl, %dl
.L4:
movw %ax, %cx
shlw $1, %cx
testw %ax, %ax
xchgw %ax, %cx
jge .L3
xorw $4129, %ax
.L3:
decb %dl
jne .L4
incw %bx
jmp .L2
.size crc16, .-crc16
.ident "GCC: (GNU) 6.3.0"

View File

@@ -1,12 +1,18 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include "polos.h"
#define kSectorsPerCluster 2 #define kSectorsPerCluster 2
#define kSectorsPerTrack 9 #define kSectorsPerTrack 9
#define kHeads 2 #define kHeads 2
#define kTracks 40
#define kFatSizeSectors 2 #define kFatSizeSectors 2
#define kRootDirSizeSectors 7 #define kRootDirSizeSectors 7
#define kBytesPerCluster 1024
#define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors) #define kDataRegionStartSector (1 + kFatSizeSectors * 2 + kRootDirSizeSectors)
#define kNumClusters ((kSectorsPerTrack * kHeads * kTracks - kDataRegionStartSector) / kSectorsPerCluster + 2)
typedef struct { typedef struct {
char name[8]; char name[8];
@@ -22,23 +28,12 @@ typedef struct {
static uint8_t* gFat; static uint8_t* gFat;
static direntry* gRootdir; static direntry* gRootdir;
static int readsector(int c, int h, int s, uint8_t* addr) { static uint8_t rwsector(uint8_t w, int c, int h, int s, void* addr) {
register uint8_t* dest asm("bx") = addr; uint16_t ret;
register uint8_t nsects asm("al") = 1; uint16_t cmd = w ? 0x0301 : 0x0201;
register uint8_t func asm("ah") = 0x02; // retry for a total of up to 3 attempts if drive not ready
register uint8_t sect asm("cl") = s;
register uint8_t cyl asm("ch") = c;
register uint8_t head asm("dh") = h;
register uint8_t drive asm("dl") = 0;
register uint16_t seg asm("es") = 0;
register uint8_t ret asm("ah");
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
asm volatile("int $0x13" ret = __readwritesector__(cmd, addr, c, h, s) >> 8;
: "=r"(ret)
: "r"(dest), "r"(nsects), "r"(func), "r"(sect), "r"(cyl),
"r"(head), "r"(drive), "r"(seg));
if (ret != 0x80) { if (ret != 0x80) {
break; break;
} }
@@ -47,6 +42,14 @@ static int readsector(int c, int h, int s, uint8_t* addr) {
return ret; return ret;
} }
static uint8_t readsector(int c, int h, int s, void* addr) {
return rwsector(0, c, h, s, addr);
}
static uint8_t writesector(int c, int h, int s, void* addr) {
return rwsector(1, c, h, s, addr);
}
static int readcluster(int cluster) { static int readcluster(int cluster) {
int offs = cluster * 3 / 2; int offs = cluster * 3 / 2;
if (cluster % 2) { if (cluster % 2) {
@@ -57,6 +60,28 @@ static int readcluster(int cluster) {
} }
} }
static int writecluster(int cluster, int value) {
int offs = cluster * 3 / 2;
if (cluster % 2) {
gFat[offs] = (gFat[offs] & 0x0f) + ((value & 0x0f) << 4);
gFat[offs+1] = value >> 4;
// high nibble is lsb + whole byte
} else {
gFat[offs] = value & 0xff;
gFat[offs+1] = (gFat[offs+1] & 0xf0) + (value >> 8);
}
return value;
}
static int firstfreecluster() {
for (int i = 2; i < kNumClusters; i++) {
if (readcluster(i) == 0) {
return i;
}
}
return -1;
}
static void cluster2chs(int cluster, int* c, int* h, int* s) { static void cluster2chs(int cluster, int* c, int* h, int* s) {
int logicalsector = int logicalsector =
kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster; kDataRegionStartSector + (cluster - 2) * kSectorsPerCluster;
@@ -65,19 +90,9 @@ static void cluster2chs(int cluster, int* c, int* h, int* s) {
*c = logicalsector / (kHeads * kSectorsPerTrack); *c = logicalsector / (kHeads * kSectorsPerTrack);
} }
static int strncmp(const char* s1, const char* s2, size_t len) {
for (int i = 0; i < len && s1[i]; i++) {
if (s1[i] != s2[i]) {
return 1;
}
}
// XXX: really we should return 0 only if *s1 == *s2 here too
return 0;
}
static int loadfile(direntry* entry, void* addr) { static int loadfile(direntry* entry, void* addr) {
int cluster = entry->cluster; int cluster = entry->cluster;
for (int i = 0; i < entry->size; i += 1024) { for (int i = 0; i < entry->size; i += kBytesPerCluster) {
int c, h, s; int c, h, s;
cluster2chs(cluster, &c, &h, &s); cluster2chs(cluster, &c, &h, &s);
if (readsector(c, h, s, addr + i)) { if (readsector(c, h, s, addr + i)) {
@@ -88,10 +103,10 @@ static int loadfile(direntry* entry, void* addr) {
s = 1; s = 1;
h++; h++;
} }
if (h > 1) { // if (h > 1) { // this will never happen
h = 0; // h = 0;
c++; // c++;
} // }
if (readsector(c, h, s, addr + i + 512)) { if (readsector(c, h, s, addr + i + 512)) {
return -5; return -5;
}; };
@@ -100,6 +115,94 @@ static int loadfile(direntry* entry, void* addr) {
return 0; return 0;
} }
static direntry* findfile(const char* name) {
direntry* file = 0;
for (int i = 0; i < 16; i++) {
direntry* entry = &gRootdir[i];
if (!strncmp(entry->name, name, 11)) {
file = entry;
break;
}
}
return file;
}
static direntry* newfile(const char* name) {
direntry* file = 0;
for (int i = 0; i < 16; i++) {
direntry* entry = &gRootdir[i];
if (entry->name[0] == 0) {
file = entry;
break;
}
}
if (!file) {
return file;
}
memcpy(file->name, name, 11);
file->size = 0;
file->cluster = 0;
return file;
}
static int allocatecluster(int previous) {
int cluster = firstfreecluster();
writecluster(cluster, 0xfff);
if (previous != 0) {
writecluster(previous, cluster);
}
return cluster;
}
static void freeclusterchain(int cluster) {
if (cluster < 2 || cluster >= 0xf00) {
return;
}
freeclusterchain(readcluster(cluster));
writecluster(cluster, 0);
}
static int savefile(direntry* file, void* addr, int size) {
freeclusterchain(file->cluster);
file->cluster = 0;
int cluster = 0;
for (int i = 0; i < size; i += kBytesPerCluster) {
cluster = allocatecluster(cluster);
if (file->cluster == 0) {
file->cluster = cluster;
}
int c, h, s;
cluster2chs(cluster, &c, &h, &s);
if (writesector(c, h, s, addr + i)) {
return -7;
}
s++;
if (s > 9) {
s = 1;
h++;
}
// if (h > 1) { // no cluster will cross a cylinder boundary
// h = 0;
// c++;
// }
if (writesector(c, h, s, addr + i + 512)) {
return -7;
};
}
file->size = size;
if (writesector(0, 0, 2, gFat)) {
return -8;
}
if (writesector(0, 0, 6, gRootdir)) {
return -9;
}
return 0;
}
int fat12_init(void* fat_addr, void* rootdir_addr) { int fat12_init(void* fat_addr, void* rootdir_addr) {
if (readsector(0, 0, 2, fat_addr)) { if (readsector(0, 0, 2, fat_addr)) {
return -2; return -2;
@@ -115,21 +218,22 @@ int fat12_init(void* fat_addr, void* rootdir_addr) {
} }
int fat12_readfile(const char* name, void* addr) { int fat12_readfile(const char* name, void* addr) {
direntry* file = 0; direntry* file = findfile(name);
for (int i = 0; i < 16; i++) {
direntry* entry = &gRootdir[i];
if (entry->name[0] == 0) {
break;
}
if (!strncmp(entry->name, name, 11)) {
file = entry;
break;
}
}
if (!file) { if (!file) {
return -4; return -4;
} }
return loadfile(file, addr); return loadfile(file, addr);
} }
int fat12_writefile(const char* name, void* addr, int size) {
direntry* file = findfile(name);
if (!file) {
file = newfile(name);
}
if (!file) {
// no moar space
return -6;
}
return savefile(file, addr, size);
}

View File

@@ -5,6 +5,16 @@
#define kDefaultChunkSize 0x20 #define kDefaultChunkSize 0x20
static int recv(uint8_t* buf, uint8_t size) {
uint16_t ds = 0;
asm volatile ("push %%ds \n\t"
"mov %0, %%ds \n\t"
"pop %0 \n" : "+r"(ds));
int len = read(kLpt1, buf, size);
asm volatile ("mov %0, %%ds" :: "r"(ds));
return len;
}
int main(int argc, uint16_t argv[]) { int main(int argc, uint16_t argv[]) {
if (argc < 2) { if (argc < 2) {
return -1; return -1;
@@ -17,17 +27,26 @@ int main(int argc, uint16_t argv[]) {
chunksize = argv[2]; chunksize = argv[2];
} }
uint8_t ok = 0x42; uint8_t ack = 0x42;
int i;
for (int i = 0; i < size;) { for (i = 0; i < size;) {
runcomms(kUntilIdle);
// delay? // delay?
int len = read(kLpt1, dest + i, chunksize); int len;
for (int j = 0; j < 3; j++) {
int r = runcomms(kUntilIdle);
len = recv(dest + i, chunksize);
if (len > 0) {
break;
}
}
if (len <= 0) { if (len <= 0) {
break; break;
} }
write(kLpt1, &ok, 1); write(kLpt1, &ack, 1);
i += len; i += len;
} }
return i;
} }

View File

@@ -1,5 +1,5 @@
SECTIONS { SECTIONS {
. = 0x1000; . = 0x1200;
.text : { .text : {
KEEP(*(.init)) KEEP(*(.init))

View File

@@ -244,7 +244,7 @@ main:
4: 4:
call sendbuffer # send input buffer call sendbuffer # send input buffer
1: 1:
mov ah, 0x07 # do parallel comms mov ax, 0x0700 # do parallel comms
int 0x80 int 0x80
mov ax, kRecvBufSize mov ax, kRecvBufSize
push ax push ax

View File

@@ -7,7 +7,7 @@
#define kFatAddr ((void*)0x1a00) #define kFatAddr ((void*)0x1a00)
#define kRootDirAddr ((void*)0x1c00) #define kRootDirAddr ((void*)0x1c00)
#define kPolmonAddr ((void*)0x1000) #define kPolmonAddr ((void*)0x1200)
#define kInt80Vector ((uint16_t*)(0x80 * 4)) #define kInt80Vector ((uint16_t*)(0x80 * 4))
#define kParallelDataPort 0x3bc #define kParallelDataPort 0x3bc
#define kParallelStatusPort 0x3bd #define kParallelStatusPort 0x3bd
@@ -18,13 +18,15 @@
void dosdbt(); void dosdbt();
void int80h(); void int80h();
uint8_t parabuf[kRecvBufferSize]; static uint8_t parabuf[kRecvBufferSize];
uint8_t parasize; static uint8_t parasize;
static void paracb(const uint8_t* buf, uint8_t size) { static void paracb(const uint8_t* buf, uint8_t size) {
// we'll mercilessly erase old data with new data if (parasize + size > sizeof(parabuf)) {
memcpy(parabuf, buf, size); size = sizeof(parabuf) - parasize;
parasize = size; }
memcpy(parabuf + parasize, buf, size);
parasize += size;
} }
static void die() { static void die() {
@@ -51,7 +53,7 @@ static void __delay__(int n) {
} }
} }
uint8_t xferpara(uint8_t until_idle) { uint16_t xferpara(uint8_t until_idle) {
do { do {
uint8_t mosib = paracomm_nextbyte(); uint8_t mosib = paracomm_nextbyte();
__outb__(kParallelDataPort, mosib); __outb__(kParallelDataPort, mosib);
@@ -65,7 +67,7 @@ uint8_t xferpara(uint8_t until_idle) {
return paracomm_busy(); return paracomm_busy();
} }
uint8_t parasend(uint8_t* addr, uint8_t size) { uint16_t parasend(uint8_t* addr, uint8_t size) {
uint8_t i; uint8_t i;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (paracomm_send(addr[i])) { if (paracomm_send(addr[i])) {
@@ -75,7 +77,7 @@ uint8_t parasend(uint8_t* addr, uint8_t size) {
return i; return i;
} }
uint8_t pararecv(uint8_t* buf, uint8_t size) { uint16_t pararecv(uint8_t* buf, uint8_t size) {
if (parasize == 0) { if (parasize == 0) {
return 0; return 0;
} }

View File

@@ -40,20 +40,6 @@ dosdbt: # assumes es=0
.section .text.int80stuff .section .text.int80stuff
# near copy [param 2] bytes, ds:[param 0] -> ds:[param 1]
copy:
mov ax, [bp-14] # ds
mov es, ax
mov ds, ax
mov cl, 4
shl si, cl
mov si, [bp+0] # source
mov di, [bp+2] # destination
mov cx, [bp+4] # length
cld
rep movsb
ret
## floppy stuff ## floppy stuff
# same as read but with a different int13h:ah value # same as read but with a different int13h:ah value
@@ -70,6 +56,7 @@ readsector:
mov ch, [bp+2] # c mov ch, [bp+2] # c
mov dh, [bp+4] # h mov dh, [bp+4] # h
mov cl, [bp+6] # s mov cl, [bp+6] # s
mov dl, 0 # drive
int 0x13 int 0x13
ret ret
@@ -121,8 +108,19 @@ readfile:
add ax, si add ax, si
mov dx, [bp+2] mov dx, [bp+2]
add dx, si add dx, si
call fat12_readfile jmp fat12_readfile
ret
# params: ds:fname, ds:src, size
writefile:
mov si, [bp-14] # ds
mov cl, 4
shl si, cl
mov ax, [bp+0]
add ax, si
mov dx, [bp+2]
add dx, si
mov cx, [bp+4]
jmp fat12_writefile
# params: ds:addr, size # params: ds:addr, size
sendpara: sendpara:
@@ -132,8 +130,7 @@ sendpara:
mov ax, [bp+0] mov ax, [bp+0]
add ax, si add ax, si
mov dx, [bp+2] mov dx, [bp+2]
call parasend jmp parasend
ret
# params: ds:addr, size # params: ds:addr, size
recvpara: recvpara:
@@ -143,7 +140,10 @@ recvpara:
mov ax, [bp+0] mov ax, [bp+0]
add ax, si add ax, si
mov dx, [bp+2] mov dx, [bp+2]
call pararecv jmp pararecv
dummy:
mov ax, -1
ret ret
.section .text.int80h .section .text.int80h
@@ -154,6 +154,7 @@ int80h:
push bp push bp
push ds push ds
push es push es
mov bp, sp
xor cx, cx xor cx, cx
mov es, cx mov es, cx
mov ds, cx mov ds, cx
@@ -162,7 +163,6 @@ int80h:
cmp cl, offset int80h_entries cmp cl, offset int80h_entries
jge 0f jge 0f
mov si, cx mov si, cx
mov bp, sp
add bp, 16 # 10 for us, 6 for the interrupt add bp, 16 # 10 for us, 6 for the interrupt
call cs:[int80h_table+si] call cs:[int80h_table+si]
jmp 1f jmp 1f
@@ -178,7 +178,7 @@ int80h:
.section .rodata.int80h .section .rodata.int80h
int80h_table: int80h_table:
.word offset copy # 0x00 .word offset dummy # 0x00
.word offset readsector # 0x01 .word offset readsector # 0x01
.word offset writesector # 0x02 .word offset writesector # 0x02
.word offset formattrack # 0x03 .word offset formattrack # 0x03
@@ -186,5 +186,6 @@ int80h_table:
.word offset recvpara # 0x05 .word offset recvpara # 0x05
.word offset sendpara # 0x06 .word offset sendpara # 0x06
.word offset xferpara # 0x07 .word offset xferpara # 0x07
.word offset writefile # 0x08
int80h_entries = . - int80h_table int80h_entries = . - int80h_table

View File

@@ -2,6 +2,8 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include "polos.h"
namespace { namespace {
constexpr int kDumpSize = 16; constexpr int kDumpSize = 16;
@@ -81,21 +83,6 @@ void WriteUint16ln(uint16_t a) {
puts("\r\n"); puts("\r\n");
} }
uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
register uint16_t ad asm("si") = addr;
register uint16_t sg asm("ds") = seg;
register uint8_t ret asm("al");
asm("lodsb \n\t" : "=r"(ret) : "r"(ad), "r"(sg));
return ret;
}
void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) {
register uint16_t ad asm("di") = addr;
register uint16_t sg asm("es") = seg;
register uint8_t v asm("al") = val;
asm("stosb \n\t" ::"r"(sg), "r"(ad), "r"(v) : "memory");
}
__attribute__((noreturn)) inline static void __basic__() { __attribute__((noreturn)) inline static void __basic__() {
asm volatile("movw $0x40, %ax \n\t" asm volatile("movw $0x40, %ax \n\t"
"mov %ax, %ds \n\t" "mov %ax, %ds \n\t"
@@ -140,23 +127,6 @@ void ClearScreen() {
: "ax", "cc"); : "ax", "cc");
} }
void Status(uint8_t status) {
asm volatile("xorb %%bh, %%bh \n\t"
"movb $0x03, %%ah \n\t"
"int $0x10 \n\t"
"mov %%dx, %%di \n\t"
"movb $0x02, %%ah \n\t"
"movw $77, %%dx \n\t"
"int $0x10 \n\t"
"movb %0, %%al \n\t"
"call %1 \n\t"
"movb $0x02, %%ah \n\t"
"movw %%di, %%dx \n\t"
"int $0x10" ::"rm"(status),
"l"(WriteUint8)
: "ax", "bh", "dx", "cx", "di", "cc");
}
char toupper(char c) { char toupper(char c) {
if (c >= 'a' && c <= 'z') { if (c >= 'a' && c <= 'z') {
return c - ('a' - 'A'); return c - ('a' - 'A');
@@ -194,34 +164,41 @@ uint16_t __readfile__(const char* name, uint16_t addr) {
return ret; return ret;
} }
uint16_t LaunchFile(const char* name, uint8_t len, uint8_t argc, uint16_t LoadFile(const char* name, uint8_t len, uint16_t seg) {
uint16_t* argv) {
constexpr uint16_t kSegment = 0x200;
constexpr uint16_t kAddress = 0x100; constexpr uint16_t kAddress = 0x100;
constexpr uint16_t kHeaderAddress = (kSegment << 4);
constexpr uint16_t kFlatAddress = (kSegment << 4) + kAddress;
constexpr uint16_t kArgvAddress = 0x0004;
// trampoline: // trampoline:
// call 0x100 // call 0x100
// retf // retf
// XXX: if you change kAddress, the trampoline needs to be updated // XXX: if you change kAddress, the trampoline needs to be updated
constexpr uint8_t kTrampoline[] = {0xe8, 0xfd, 0x00, 0xcb}; constexpr uint8_t kTrampoline[] = {0xe8, 0xfd, 0x00, 0xcb};
uint16_t headeraddr = (seg << 4);
uint16_t flataddr = headeraddr + kAddress;
char fatname[11]; char fatname[11];
tofatname(name, len, fatname); tofatname(name, len, fatname);
uint16_t r = __readfile__(fatname, kFlatAddress); uint16_t r = __readfile__(fatname, flataddr);
if (r) { if (r) {
memcpy(fatname + 8, "COM", 3); memcpy(fatname + 8, "COM", 3);
r = __readfile__(fatname, kFlatAddress); r = __readfile__(fatname, flataddr);
} }
if (r) { if (r) {
return r; return r;
} }
auto* ptr = reinterpret_cast<uint8_t*>(kHeaderAddress); auto* ptr = reinterpret_cast<uint8_t*>(headeraddr);
memcpy(ptr, kTrampoline, sizeof(kTrampoline)); memcpy(ptr, kTrampoline, sizeof(kTrampoline));
auto* argp = reinterpret_cast<uint16_t*>(kHeaderAddress + kArgvAddress);
return 0;
}
uint16_t Exec(uint16_t seg, uint8_t argc, uint16_t* argv) {
constexpr uint16_t kAddress = 0x100;
constexpr uint16_t kArgvAddress = 0x0004;
uint16_t headeraddr = (seg << 4);
auto* argp = reinterpret_cast<uint16_t*>(headeraddr + kArgvAddress);
memcpy(argp, argv, argc * 2); memcpy(argp, argv, argc * 2);
register uint16_t ac asm("ax") = argc; register uint16_t ac asm("ax") = argc;
@@ -235,8 +212,13 @@ uint16_t LaunchFile(const char* name, uint8_t len, uint8_t argc,
"xchg %%cx, %%sp \n\t" "xchg %%cx, %%sp \n\t"
"sti \n\t" "sti \n\t"
"push %%cx \n\t" "push %%cx \n\t"
"lcall %2,$0 \n\t" "push %2 \n\t"
"xor %%cx, %%cx \n\t" "xor %%cx, %%cx \n\t"
"push %%cx \n\t"
"mov %%sp, %%bx \n\t"
"lcall *(%%bx) \n\t"
"pop %%cx \n\t"
"pop %%dx \n\t"
"mov %%cx, %%ds \n\t" "mov %%cx, %%ds \n\t"
"mov %%cx, %%es \n\t" "mov %%cx, %%es \n\t"
"cli \n\t" "cli \n\t"
@@ -244,7 +226,7 @@ uint16_t LaunchFile(const char* name, uint8_t len, uint8_t argc,
"mov %%cx, %%ss \n\t" "mov %%cx, %%ss \n\t"
"sti" "sti"
: "+r"(ac), "+r"(av) : "+r"(ac), "+r"(av)
: "i"(kSegment), "i"(kAddress) : "r"(seg), "i"(kAddress)
: "bx", "cx", "memory", "cc"); : "bx", "cx", "memory", "cc");
return ac; return ac;
@@ -258,7 +240,7 @@ asm(" .section .text.cbreak \n"
" xor %ax, %ax \n" " xor %ax, %ax \n"
" mov %ax, %ds \n" " mov %ax, %ds \n"
" cli \n" " cli \n"
" mov %ax, %ds \n" " mov %ax, %ss \n"
" mov $0x2000, %sp \n" " mov $0x2000, %sp \n"
" sti \n" " sti \n"
" pushf \n" " pushf \n"
@@ -275,13 +257,43 @@ void InstallCtrlBreak() {
vec[1] = 0; vec[1] = 0;
} }
// j
// w [u8]*
// i [u16] [u16]*
// r str [u16]*
// k u16 u16 u16
int ReadArgs(const char*& ptr, uint16_t* args, int size) {
int nargs = 0;
while (*ptr && nargs < size) {
if (*ptr == ' ') {
ptr += 1;
continue;
}
args[nargs] = ReadUint16(ptr);
nargs += 1;
}
return nargs;
}
int ReadString(const char*& ptr, const char*& str) {
while (*ptr == ' ') {
ptr++;
}
str = ptr;
int l;
for (l = 0; *ptr && *ptr != ' '; l++, ptr++) {
}
return l;
}
bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) { bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
bool dump = true; bool dump = true;
for (const char* ptr = buf; *ptr;) { for (const char* ptr = buf; *ptr;) {
if (*ptr == 's') { if (*ptr == 's') {
cur_addr = 0;
ptr += 1; ptr += 1;
cur_seg = ReadUint16(ptr); cur_addr = 0;
ReadArgs(ptr, &cur_seg, 1);
} else if (*ptr == '$') { } else if (*ptr == '$') {
__basic__(); __basic__();
} else if (*ptr == 'j') { } else if (*ptr == 'j') {
@@ -292,44 +304,27 @@ bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
WriteUint16ln(ret); WriteUint16ln(ret);
} else if (*ptr == 'i') { } else if (*ptr == 'i') {
dump = false; dump = false;
uint16_t args[8]; // ought to be enough for everybody
uint8_t nargs = 0;
ptr++; ptr++;
int fun = ReadUint8(ptr) << 8; uint16_t args[8]; // ought to be enough for everybody
fun += ReadUint8(ptr); int nargs = ReadArgs(ptr, args, 8);
for (; *ptr && nargs < 8;) { uint16_t fun = args[0];
if (*ptr == ' ') { uint16_t ret = Int80h(fun, nargs - 1, args + 1);
ptr++;
continue;
}
args[nargs++] = ReadUint16(ptr);
}
uint16_t ret = Int80h(fun, nargs, args);
WriteUint16ln(ret); WriteUint16ln(ret);
} else if (*ptr == 'l') { } else if (*ptr == 'l') {
dump = false; dump = false;
ClearScreen();
ptr++; ptr++;
const char* fname;
int l = ReadString(ptr, fname);
uint16_t ret = LoadFile(fname, l, cur_seg);
if (ret) {
WriteUint16ln(ret);
}
} else if (*ptr == 'r') { } else if (*ptr == 'r') {
dump = false; dump = false;
uint16_t args[8]; // ought to be enough for everybody
uint8_t nargs = 0;
ptr++; ptr++;
while (*ptr == ' ') { uint16_t args[8]; // ought to be enough for everybody
ptr++; int nargs = ReadArgs(ptr, args, 8);
} uint16_t ret = Exec(cur_seg, nargs, args);
const char* fname = ptr;
int l;
for (l = 0; *ptr && *ptr != ' '; l++, ptr++) {
}
for (; *ptr && nargs < 8;) {
if (*ptr == ' ') {
ptr++;
continue;
}
args[nargs++] = ReadUint16(ptr);
}
uint16_t ret = LaunchFile(fname, l, nargs, args);
WriteUint16ln(ret); WriteUint16ln(ret);
} else if (*ptr == 'w') { } else if (*ptr == 'w') {
dump = false; dump = false;
@@ -344,6 +339,17 @@ bool ParseCommand(const char* buf, uint16_t& cur_addr, uint16_t& cur_seg) {
__set_far_u8__(addr, cur_seg, d); __set_far_u8__(addr, cur_seg, d);
addr++; addr++;
} }
} else if (*ptr == 'k') {
dump = false;
ptr++;
uint16_t args[2];
// TODO: implement copy on non-zero segments
if (cur_seg == 0 && ReadArgs(ptr, args, 2) == 2) {
auto* src = reinterpret_cast<uint8_t*>(args[0]);
uint16_t size = args[1];
auto* dest = reinterpret_cast<uint8_t*>(cur_addr);
memcpy(dest, src, size);
}
} else { } else {
cur_addr = ReadUint16(ptr); cur_addr = ReadUint16(ptr);
} }

View File

@@ -8,6 +8,9 @@
int runcomms(char until_idle); int runcomms(char until_idle);
int putchar(int);
int puts(const char*);
inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) { inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
register uint16_t ad asm("di") = addr; register uint16_t ad asm("di") = addr;
register uint8_t ret asm("al"); register uint8_t ret asm("al");
@@ -18,3 +21,39 @@ inline static uint8_t __get_far_u8__(uint16_t addr, uint16_t seg) {
: "es"); : "es");
return ret; return ret;
} }
inline static void __set_far_u8__(uint16_t addr, uint16_t seg, uint8_t val) {
register uint16_t ad asm("di") = addr;
register uint8_t v asm("al") = val;
asm("mov %0, %%es \t\n"
"stosb \n\t" ::"r"(seg), "r"(ad), "r"(v) : "es", "memory");
}
inline static uint16_t __readwritesector__(uint16_t cmd, uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) {
register uint8_t* dest asm("bx") = addr;
register uint8_t sect asm("cl") = s;
register uint8_t cyl asm("ch") = c;
register uint8_t head asm("dh") = h;
register uint8_t drive asm("dl") = 0;
register uint16_t ret asm("ax");
asm volatile("xor %%ax, %%ax \n\t"
"mov %%ax, %%es \n\t"
"mov %1, %%ax \n\t"
"int $0x13"
: "=r"(ret)
: "ir"(cmd), "r"(dest), "r"(sect), "r"(cyl),
"r"(head), "r"(drive)
);
return ret;
}
inline static uint16_t __readsector__(uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) {
return __readwritesector__(0x0201, addr, c, h, s);
}
inline static uint16_t __writesector__(uint8_t* addr, uint8_t c, uint8_t h, uint8_t s) {
return __readwritesector__(0x0301, addr, c, h, s);
}

View File

@@ -46,7 +46,17 @@ void* memset(void* ptr, int val, size_t len) {
return ptr; return ptr;
} }
int _int80h_2(uint8_t fun, uint16_t arg1, uint16_t arg2) { int strncmp(const char* s1, const char* s2, size_t len) {
for (int i = 0; i < len && s1[i]; i++) {
if (s1[i] != s2[i]) {
return 1;
}
}
// XXX: really we should return 0 only if *s1 == *s2 here too
return 0;
}
static int int80h_2(uint8_t fun, uint16_t arg1, uint16_t arg2) {
register uint16_t a1 asm("dx") = arg1; register uint16_t a1 asm("dx") = arg1;
register uint16_t a2 asm("cx") = arg2; register uint16_t a2 asm("cx") = arg2;
register uint8_t ah asm("ah") = fun; register uint8_t ah asm("ah") = fun;
@@ -69,7 +79,7 @@ int runcomms(char until_idle) {
asm volatile("mov $0x07, %%ah \n\t" asm volatile("mov $0x07, %%ah \n\t"
"int $0x80 \n\t" "int $0x80 \n\t"
: "=r"(ret) : "=r"(ret)
: "r"(until_idle) : "r"(ui)
: "bx", "cx", "dx", "cc", "memory"); : "bx", "cx", "dx", "cc", "memory");
return ret; return ret;
@@ -79,12 +89,12 @@ int read(int fd, void* buf, size_t size) {
if (fd != kLpt1) { if (fd != kLpt1) {
return -1; return -1;
} }
return _int80h_2(0x05, (uint16_t)buf, size); return int80h_2(0x05, (uint16_t)buf, size);
} }
int write(int fd, void* buf, size_t size) { int write(int fd, void* buf, size_t size) {
if (fd != kLpt1) { if (fd != kLpt1) {
return -1; return -1;
} }
return _int80h_2(0x06, (uint16_t)buf, size); return int80h_2(0x06, (uint16_t)buf, size);
} }