From 9b297ddabcf8f3f7d92f825705daa3bf671614e4 Mon Sep 17 00:00:00 2001 From: hpa Date: Sun, 23 Nov 2003 01:38:19 +0000 Subject: [PATCH] Fix the file read API for COMBOOT/COM32 --- NEWS | 3 + com32.inc | 2 + comboot.doc | 1 - comboot.inc | 5 +- sample/Makefile | 12 +- sample/conio.c | 372 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ sample/filetest.c | 73 ++++++++--- 7 files changed, 447 insertions(+), 21 deletions(-) create mode 100644 sample/conio.c diff --git a/NEWS b/NEWS index d80099e..78d8217 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,9 @@ Changes in 2.07: * PXELINUX: PXELINUX-specific options are now recognized both in a vendor-option-space (a.k.a. type 43 encapsulated) as well as in a site-option-space (unencapsulated.) + * COM32: Don't crash when DS != 0. + * COMBOOT/COM32: Make file reading work correctly. Thanks to + Phung Chi Kien for submitting a test program. Changes in 2.06: * ALL: Fix problem that would occationally cause a diff --git a/com32.inc b/com32.inc index 969bfce..59d1cb8 100644 --- a/com32.inc +++ b/com32.inc @@ -56,6 +56,8 @@ com32_start: com32_enter_pm: cli + mov ax,cs + mov ds,ax mov [SavedSSSP],sp mov [SavedSSSP+2],ss cld diff --git a/comboot.doc b/comboot.doc index 96155ba..89fe6e4 100644 --- a/comboot.doc +++ b/comboot.doc @@ -446,4 +446,3 @@ AX=000Ch Perform final cleanup All other values are undefined, and may have different meanings in future versions of SYSLINUX. - diff --git a/comboot.inc b/comboot.inc index 2e768ea..454d42c 100644 --- a/comboot.inc +++ b/comboot.inc @@ -409,6 +409,7 @@ comapi_open: mov P_HAX,dx mov ax,[ClustSize] mov P_CX,ax + mov P_SI,si clc ret .err: @@ -420,8 +421,10 @@ comapi_open: ; INT 22h AX=0007h Read file ; comapi_read: - mov ax,P_BX + mov es,P_ES + mov bx,P_BX mov si,P_SI + mov cx,P_CX call getfssec jnc .noteof xor si,si ; SI <- 0 on EOF, CF <- 0 diff --git a/sample/Makefile b/sample/Makefile index 35ee378..0d23c98 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -17,11 +17,16 @@ CC = gcc LD = ld +AR = ar +RANLIB = ranlib CFLAGS = -march=i386 -O2 -fomit-frame-pointer -I../com32/include SFLAGS = -march=i386 LDFLAGS = -s OBJCOPY = objcopy PPMTOLSS16 = ../ppmtolss16 +LIB = libcom32.a + +LIBOBJS = conio.o .SUFFIXES: .lss .c .o .elf .c32 @@ -33,12 +38,17 @@ all: syslogo.lss hello.c32 hello2.c32 filetest.c32 %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< -%.elf: c32entry.o %.o +%.elf: c32entry.o %.o $(LIB) $(LD) -Ttext 0x101000 -e _start -o $@ $^ %.c32: %.elf $(OBJCOPY) -O binary $< $@ +$(LIB): $(LIBOBJS) + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ + syslogo.lss: syslogo.png $(PPMTOLSS16) pngtopnm syslogo.png | \ $(PPMTOLSS16) \#000000=0 \#d0d0d0=7 \#f6f6f6=15 \ diff --git a/sample/conio.c b/sample/conio.c new file mode 100644 index 0000000..9126bc7 --- /dev/null +++ b/sample/conio.c @@ -0,0 +1,372 @@ +#ident "$Id$" +/* ----------------------------------------------------------------------- * + * + * Copyright 2001-2003 H. Peter Anvin - All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Bostom MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * conio.c + * + * Output to the screen + * + * FIX THIS: Replace printf() implementation with BSD/MIT-licensed one + * from klibc + */ + +#include +#include + +#define NULL ((void *)0) + +int putchar(int ch) +{ + com32sys_t regs; + + memset(®s, 0, sizeof regs); + + if ( ch == '\n' ) { + /* \n -> \r\n */ + putchar('\r'); + } + + regs.eax.b[1] = 0x02; + regs.edx.b[0] = ch; + __com32.cs_intcall(0x21, ®s, NULL); + + return ch; +} + +int puts(const char *s) +{ + int count = 0; + + while ( *s ) { + putchar(*s); + count++; + s++; + } + + return count; +} + +/* + * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just + * initialization code anyway, so it doesn't take up space when we're + * actually running. This version of printf() does not include 64-bit + * support. "Live with it." + * + * Most of this code was shamelessly snarfed from the Linux kernel, then + * modified. + */ + +static inline int +isdigit(int ch) +{ + return (ch >= '0') && (ch <= '9'); +} + +static int skip_atoi(const char **s) +{ + int i=0; + + while (isdigit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +unsigned int atou(const char *s) +{ + unsigned int i = 0; + while (isdigit(*s)) + i = i*10 + (*s++ - '0'); + return i; +} + +static int strnlen(const char *s, int maxlen) +{ + const char *es = s; + while ( *es && maxlen ) { + es++; maxlen--; + } + + return (es-s); +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (isdigit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (isdigit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + +int printf(const char *fmt, ...) +{ + char printf_buf[1024]; + va_list args; + int printed; + + va_start(args, fmt); + printed = vsprintf(printf_buf, fmt, args); + va_end(args); + + puts(printf_buf); + + return printed; +} + diff --git a/sample/filetest.c b/sample/filetest.c index 52c5ea2..c570138 100644 --- a/sample/filetest.c +++ b/sample/filetest.c @@ -1,6 +1,8 @@ #include +#include #define NULL ((void *)0) +int printf(const char *, ...); static inline void memset(void *buf, int ch, unsigned int len) { @@ -16,45 +18,80 @@ static void strcpy(char *dst, const char *src) *dst = '\0'; } +static void printregs(const com32sys_t *r) +{ + printf("eflags = %08x ds = %04x es = %04x fs = %04x gs = %04x\n" + "eax = %08x ebx = %08x ecx = %08x edx = %08x\n" + "ebp = %08x esi = %08x edi = %08x esp = %08x\n", + r->eflags.l, r->ds, r->es, r->fs, r->gs, + r->eax.l, r->ebx.l, r->ecx.l, r->edx.l, + r->ebp.l, r->esi.l, r->edi.l, r->_unused.l); +} + int __start(void) { unsigned int ax,cx,dx,es,si,di,t; com32sys_t inreg,outreg; + char *p; + /* Test null system call */ + inreg.eflags.l = 0xffffffff; + inreg.eax.l = 0x11110000; + inreg.ecx.l = 0x22222222; + inreg.edx.l = 0x33333333; + inreg.ebx.l = 0x44444444; + inreg.ebp.l = 0x55555555; + inreg.esi.l = 0x66666666; + inreg.edi.l = 0x77777777; + inreg.ds = 0xaaaa; + inreg.es = 0xbbbb; + inreg.fs = 0xcccc; + inreg.gs = 0xdddd; + printregs(&inreg); + __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); + memset(&inreg, 0, sizeof inreg); memset(&outreg, 0, sizeof outreg); strcpy(__com32.cs_bounce, "test.txt"); inreg.eax.w[0] = 0x0006; // Open file inreg.esi.w[0] = OFFS(__com32.cs_bounce); inreg.es = SEG(__com32.cs_bounce); + printregs(&inreg); __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); - si = outreg.esi.w[0]; - cx = outreg.ecx.w[0]; - ax = outreg.eax.l; - - if ( ax > 65536 ) - ax = 65536; /* Max in one call */ + si = outreg.esi.w[0]; /* File handle */ + cx = outreg.ecx.w[0]; /* Block size */ + ax = outreg.eax.l; /* File length */ while ( si ) { - t = (ax+cx-1)/cx; - + /* We can only read 64K per call */ + t = ( ax > 65536 ) ? 65536/cx : (ax+cx-1)/cx; + memset(&inreg, 0, sizeof inreg); inreg.esi.w[0] = si; - inreg.ecx.w[0] = t; + inreg.ecx.w[0] = t; /* Block count */ inreg.eax.w[0] = 0x0007; // Read file inreg.ebx.w[0] = OFFS(__com32.cs_bounce); inreg.es = SEG(__com32.cs_bounce); - __com32.cs_intcall(0x22, &inreg, &inreg); - si = inreg.esi.w[0]; + printregs(&inreg); + __com32.cs_intcall(0x22, &inreg, &outreg); + printregs(&outreg); + printf("----\n"); + si = outreg.esi.w[0]; - // This is broken if we hit null, but works for (DOS) text files - memset(&inreg, 0, sizeof inreg); - inreg.eax.w[0] = 0x0002; - inreg.ebx.w[0] = OFFS(__com32.cs_bounce); - inreg.es = SEG(__com32.cs_bounce); - __com32.cs_intcall(0x22, &inreg, NULL); + /* Print the buffer */ + t = (ax < 65536) ? ax : 65536; + p = __com32.cs_bounce; + while ( t ) { + putchar(*p++); + t--; + ax--; + } } - + return 0; } -- 2.7.4