Fix the file read API for COMBOOT/COM32
authorhpa <hpa>
Sun, 23 Nov 2003 01:38:19 +0000 (01:38 +0000)
committerhpa <hpa>
Sun, 23 Nov 2003 01:38:19 +0000 (01:38 +0000)
NEWS
com32.inc
comboot.doc
comboot.inc
sample/Makefile
sample/conio.c [new file with mode: 0644]
sample/filetest.c

diff --git a/NEWS b/NEWS
index d80099e..78d8217 100644 (file)
--- 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
index 969bfce..59d1cb8 100644 (file)
--- 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
index 96155ba..89fe6e4 100644 (file)
@@ -446,4 +446,3 @@ AX=000Ch    Perform final cleanup
 
        All other values are undefined, and may have different
        meanings in future versions of SYSLINUX.
-
index 2e768ea..454d42c 100644 (file)
@@ -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
index 35ee378..0d23c98 100644 (file)
 
 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 (file)
index 0000000..9126bc7
--- /dev/null
@@ -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 <com32.h>
+#include <stdarg.h>
+
+#define NULL ((void *)0)
+
+int putchar(int ch)
+{
+  com32sys_t regs;
+
+  memset(&regs, 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, &regs, 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;
+}
+
index 52c5ea2..c570138 100644 (file)
@@ -1,6 +1,8 @@
 #include <com32.h>
+#include <stdarg.h>
 
 #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;
 }