memdump: a debugging utility to dump memory over a serial port
authorH. Peter Anvin <hpa@zytor.com>
Fri, 21 Sep 2007 23:52:35 +0000 (16:52 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Fri, 21 Sep 2007 23:52:35 +0000 (16:52 -0700)
A memory-dumping utility which runs in real mode.  Thus, it can be
used to get memory dumps from a relatively pristine system.

27 files changed:
Makefile
memdump/Makefile [new file with mode: 0644]
memdump/README [new file with mode: 0644]
memdump/__divdi3.c [new file with mode: 0644]
memdump/__udivmoddi4.c [new file with mode: 0644]
memdump/argv.c [new file with mode: 0644]
memdump/code16.h [new file with mode: 0644]
memdump/com16.ld [new file with mode: 0644]
memdump/conio.c [new file with mode: 0644]
memdump/crt0.S [new file with mode: 0644]
memdump/errno.h [new file with mode: 0644]
memdump/io.h [new file with mode: 0644]
memdump/main.c [new file with mode: 0644]
memdump/malloc.h [new file with mode: 0644]
memdump/memcpy.S [new file with mode: 0644]
memdump/memset.S [new file with mode: 0644]
memdump/mystuff.h [new file with mode: 0644]
memdump/printf.c [new file with mode: 0644]
memdump/serial.c [new file with mode: 0644]
memdump/skipatou.c [new file with mode: 0644]
memdump/stdio.h [new file with mode: 0644]
memdump/stdlib.h [new file with mode: 0644]
memdump/string.h [new file with mode: 0644]
memdump/strtoul.c [new file with mode: 0644]
memdump/ymodem.txt [new file with mode: 0644]
memdump/ymsend.c [new file with mode: 0644]
memdump/ymsend.h [new file with mode: 0644]

index 03e69fd..0bd2121 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -73,11 +73,12 @@ BTARGET  = kwdhash.gen version.gen version.h \
           ldlinux.bss ldlinux.sys ldlinux.bin \
           pxelinux.0 isolinux.bin isolinux-debug.bin \
           extlinux.bin extlinux.bss extlinux.sys
-BOBJECTS = $(BTARGET) mbr/mbr.bin dos/syslinux.com win32/syslinux.exe memdisk/memdisk
+BOBJECTS = $(BTARGET) mbr/mbr.bin dos/syslinux.com win32/syslinux.exe \
+       memdisk/memdisk memdump/memdump.com
 # BESUBDIRS and IESUBDIRS are "early", i.e. before the root; BSUBDIRS
 # and ISUBDIRS are "late", after the root.
 BESUBDIRS = mbr
-BSUBDIRS = memdisk dos win32
+BSUBDIRS = memdisk memdump dos win32
 ITARGET  = copybs.com gethostip mkdiskimage
 IOBJECTS = $(ITARGET) mtools/syslinux unix/syslinux extlinux/extlinux
 IESUBDIRS =
diff --git a/memdump/Makefile b/memdump/Makefile
new file mode 100644 (file)
index 0000000..4049702
--- /dev/null
@@ -0,0 +1,64 @@
+TMPFILE = $(shell mktemp /tmp/gcc_ok.XXXXXX)
+
+gcc_ok   = $(shell tmpf=$(TMPFILE); if gcc $(1) -c -x c /dev/null -o $$tmpf 2>/dev/null; \
+                  then echo $(1); else echo $(2); fi; rm -f $$tmpf)
+
+M32       := $(call gcc_ok,-m32,) $(call gcc_ok,-ffreestanding,) $(call gcc_ok,-fno-stack-protector,)
+
+CC      = gcc
+LD       = ld -m elf_i386
+OBJCOPY  = objcopy
+OPTFLAGS = -g -Os -march=i386 -falign-functions=0 -falign-jumps=0 -falign-loops=0 -fomit-frame-pointer
+INCLUDES = -include code16.h -I.
+CFLAGS  = $(M32) -mregparm=3 -DREGPARM=3 -W -Wall -msoft-float $(OPTFLAGS) $(INCLUDES)
+LDFLAGS         = -T com16.ld
+AR       = ar
+RANLIB   = ranlib
+LIBGCC  := $(shell $(CC) --print-libgcc)
+
+SRCS     = main.c serial.c ymsend.c
+OBJS    = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS)))
+LIBOBJS         = conio.o memcpy.o memset.o skipatou.o strtoul.o \
+          argv.o printf.o __divdi3.o __udivmoddi4.o
+
+.SUFFIXES: .c .o .i .s .S .elf .com
+
+VPATH = .:..:../libfat
+
+TARGETS = memdump.com
+
+all: $(TARGETS)
+
+tidy:
+       -rm -f *.o *.i *.s *.a .*.d *.elf
+
+clean: tidy
+
+spotless: clean
+       -rm -f *~ $(TARGETS)
+
+installer:
+
+memdump.elf: $(OBJS) libcom.a
+       $(LD) $(LDFLAGS) -o $@ $^
+
+libcom.a: $(LIBOBJS)
+       -rm -f $@
+       $(AR) cq $@ $^
+       $(RANLIB) $@
+
+memdump.com: memdump.elf
+       $(OBJCOPY) -O binary $< $@
+
+%.o: %.c
+       $(CC) -Wp,-MT,$@,-MD,.$@.d $(CFLAGS) -c -o $@ $<
+%.i: %.c
+       $(CC) $(CFLAGS) -E -o $@ $<
+%.s: %.c
+       $(CC) $(CFLAGS) -S -o $@ $<
+%.o: %.S
+       $(CC) -Wp,-MT,$@,-MD,.$@.d $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
+%.s: %.S
+       $(CC) $(CFLAGS) -E -o $@ $<
+
+-include .*.d
diff --git a/memdump/README b/memdump/README
new file mode 100644 (file)
index 0000000..2b82577
--- /dev/null
@@ -0,0 +1,19 @@
+This is a very simple COMBOOT program which can be used to dump memory
+regions over a serial port.  To use it, type on the SYSLINUX command
+line:
+
+memdump <port> <prefix> <start>,<len> <start>,<len>...
+
+For example:
+
+memdump 0 funnysystem- 0,0x600 0x9fc00,0x400 0xf0000,0x10000
+
+... dumps three memory ranges (the standard BIOS memory ranges, often
+useful) onto serial port 0.  The <port> can either be in the range 0-3
+for the standard BIOS serial port, or the I/O address of the UART.
+
+The data is transferred using the YMODEM protocol; the Unix
+implementation of this protocol is called "rb" and is part of the
+"lrzsz" (or "rzsz") package.  If one uses a terminal program like
+Minicom, there is often a way to invoke it from inside the terminal
+program; in Minicom, this is done with the Ctrl-A R control sequence.
diff --git a/memdump/__divdi3.c b/memdump/__divdi3.c
new file mode 100644 (file)
index 0000000..3641396
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem);
+
+int64_t __divdi3(int64_t num, int64_t den)
+{
+  int minus = 0;
+  int64_t v;
+
+  if ( num < 0 ) {
+    num = -num;
+    minus = 1;
+  }
+  if ( den < 0 ) {
+    den = -den;
+    minus ^= 1;
+  }
+
+  v = __udivmoddi4(num, den, NULL);
+  if ( minus )
+    v = -v;
+
+  return v;
+}
diff --git a/memdump/__udivmoddi4.c b/memdump/__udivmoddi4.c
new file mode 100644 (file)
index 0000000..8e7661f
--- /dev/null
@@ -0,0 +1,31 @@
+#include <stdint.h>
+
+uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t *rem_p)
+{
+  uint64_t quot = 0, qbit = 1;
+
+  if ( den == 0 ) {
+    asm volatile("int $0");
+    return 0;                  /* If trap returns... */
+  }
+
+  /* Left-justify denominator and count shift */
+  while ( (int64_t)den >= 0 ) {
+    den <<= 1;
+    qbit <<= 1;
+  }
+
+  while ( qbit ) {
+    if ( den <= num ) {
+      num -= den;
+      quot += qbit;
+    }
+    den >>= 1;
+    qbit >>= 1;
+  }
+
+  if ( rem_p )
+    *rem_p = num;
+
+  return quot;
+}
diff --git a/memdump/argv.c b/memdump/argv.c
new file mode 100644 (file)
index 0000000..9aaa4d3
--- /dev/null
@@ -0,0 +1,92 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2004 H. Peter Anvin - All Rights Reserved
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * argv.c
+ *
+ * Parse a single C string into argc and argv (argc is return value.)
+ * memptr points to available memory.
+ */
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define ALIGN_UP(p,t)       ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1)))
+
+extern char _end[];         /* Symbol created by linker */
+void *__mem_end = &_end;     /* Global variable for use by malloc() */
+
+int __parse_argv(char ***argv, const char *str)
+{
+  char *mem = __mem_end;
+  const char *p = str;
+  char *q = mem;
+  char *r;
+  char **arg;
+  int wasspace = 0;
+  int argc = 1;
+
+  /* First copy the string, turning whitespace runs into nulls */
+  for ( p = str ; ; p++ ) {
+    if ( *p <= ' ' ) {
+      if ( !wasspace ) {
+       wasspace = 1;
+       *q++ = '\0';
+      }
+    } else {
+      if ( wasspace ) {
+       argc++;
+       wasspace = 0;
+      }
+      *q++ = *p;
+    }
+
+    /* This test is AFTER we have processed the null byte;
+       we treat it as a whitespace character so it terminates
+       the last argument */
+    if ( ! *p )
+      break;
+  }
+
+  /* Now create argv */
+  arg = ALIGN_UP(q,char *);
+  *argv = arg;
+  *arg++ = mem;                        /* argv[0] */
+
+  q--;                         /* Point q to final null */
+  for ( r = mem ; r < q ; r++ ) {
+    if ( *r == '\0' ) {
+      *arg++ = r+1;
+    }
+  }
+
+  *arg++ = NULL;               /* Null pointer at the end */
+  __mem_end = arg;             /* End of memory we used */
+
+  return argc;
+}
diff --git a/memdump/code16.h b/memdump/code16.h
new file mode 100644 (file)
index 0000000..ca76565
--- /dev/null
@@ -0,0 +1,6 @@
+/* Must be included first of all */
+#ifdef __ASSEMBLY__
+       .code16
+#else
+__asm__ (".code16gcc");
+#endif
diff --git a/memdump/com16.ld b/memdump/com16.ld
new file mode 100644 (file)
index 0000000..08a1e95
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Linker script for COM16 binaries
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+             "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x100;
+  PROVIDE (__executable_start = .);
+
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+  } =0x90909090
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x90909090
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(4);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  PROVIDE (__ctors_start = .);
+  .ctors          :
+  {
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  PROVIDE (__ctors_end = .);
+  PROVIDE (__dtors_start = .);
+  .dtors          :
+  {
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  PROVIDE (__dtors_end = .);
+
+  /* Adjust the address for the data segment.  Avoid mixing code and
+     data within same 128-byte chunk. */
+  . = ALIGN(128);
+
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .;
+  PROVIDE (edata = .);
+  __bss_start = .;
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.  */
+   . = ALIGN(32 / 8);
+  }
+  . = ALIGN(32 / 8);
+  _end = .;
+  PROVIDE (end = .);
+
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdump/conio.c b/memdump/conio.c
new file mode 100644 (file)
index 0000000..4d58dcb
--- /dev/null
@@ -0,0 +1,42 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2001-2004 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,
+ *   Boston 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
+ */
+
+#include <stdarg.h>
+#include "mystuff.h"
+
+int putchar(int ch)
+{
+  if ( ch == '\n' )
+    putchar('\r');
+  asm("movb $0x02,%%ah ; int $0x21" : : "d" (ch));
+  return ch;
+}
+
+/* Note: doesn't put '\n' like the stdc version does */
+int puts(const char *s)
+{
+  int count = 0;
+
+  while ( *s ) {
+    putchar(*s);
+    count++;
+    s++;
+  }
+
+  return count;
+}
diff --git a/memdump/crt0.S b/memdump/crt0.S
new file mode 100644 (file)
index 0000000..92297ec
--- /dev/null
@@ -0,0 +1,53 @@
+       .code16
+
+#ifndef REGPARM
+# error "This file assumes -mregparm=3 -DREGPARM=3"
+#endif
+
+       .section ".init","ax"
+       .globl _start
+       .type _start,@function
+_start:
+       # Align the stack and make sure the high half is zero
+       andl $0xfff8,%esp
+
+       # Clear the .bss
+       cld
+       xorl %eax,%eax
+       movw $__bss_start,%di
+       movw $_end+3,%cx
+       subw %di,%cx
+       shrw $2,%cx
+       rep ; stosl
+
+       # Compute argc and argv (assumes REGPARM)
+       xorl %edx,%edx
+       movzbw 0x80,%bx
+       movb %dl,0x81(%bx)      # Zero-terminate string
+       movb $0x81,%dl
+       pushl %eax              # Make space for argv
+       movl %esp,%eax
+       calll __parse_argv
+       pushl %eax              # argc
+
+       # Initialize malloc
+       # calll __init_memory_arena
+
+       # Now call main... (NOTE: gcc forces main to be regparm 0)
+       popl %eax               # argc
+       popl %edx               # argv
+       calll main
+
+       # Here %eax is the exit code, fall through into exit
+
+       .size _start,.-_start
+
+       .globl exit
+       .type exit,@function
+exit:
+       # Exit code already in %eax
+       movb $0x4c,%ah          # Terminate program
+       int $0x21
+1:     hlt
+       jmp 1b
+       .size exit,.-exit
diff --git a/memdump/errno.h b/memdump/errno.h
new file mode 100644 (file)
index 0000000..30aa046
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef ERRNO_H
+#define ERRNO_H
+
+int errno;
+void perror(const char *);
+
+#endif /* ERRNO_H */
diff --git a/memdump/io.h b/memdump/io.h
new file mode 100644 (file)
index 0000000..a592402
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef IO_H
+#define IO_H
+
+static inline void outb(unsigned char v, unsigned short p)
+{
+  asm volatile("outb %1,%0" : : "d" (p), "a" (v));
+}
+
+static inline unsigned char inb(unsigned short p)
+{
+  unsigned char v;
+  asm volatile("inb %1,%0" : "=a" (v) : "d" (p));
+  return v;
+}
+
+static inline void outw(unsigned short v, unsigned short p)
+{
+  asm volatile("outw %1,%0" : : "d" (p), "a" (v));
+}
+
+static inline unsigned short inw(unsigned short p)
+{
+  unsigned short v;
+  asm volatile("inw %1,%0" : "=a" (v) : "d" (p));
+  return v;
+}
+
+static inline void outl(unsigned int v, unsigned short p)
+{
+  asm volatile("outl %1,%0" : : "d" (p), "a" (v));
+}
+
+static inline unsigned int inl(unsigned short p)
+{
+  unsigned int v;
+  asm volatile("inl %1,%0" : "=a" (v) : "d" (p));
+  return v;
+}
+
+#endif
diff --git a/memdump/main.c b/memdump/main.c
new file mode 100644 (file)
index 0000000..c8fa39d
--- /dev/null
@@ -0,0 +1,153 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007 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,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mystuff.h"
+#include "ymsend.h"
+#include "io.h"
+
+const char *program = "memdump";
+
+void __attribute__((noreturn)) die(const char *msg)
+{
+  puts(program);
+  puts(": ");
+  puts(msg);
+  putchar('\n');
+  exit(1);
+}
+
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
+static inline __attribute__((const)) uint16_t ds(void)
+{
+  uint16_t v;
+  asm("movw %%ds,%0" : "=rm" (v));
+  return v;
+}
+
+#define GDT_ENTRY(flags,base,limit)            \
+       (((uint64_t)(base & 0xff000000) << 32) |        \
+        ((uint64_t)flags << 40) |                      \
+        ((uint64_t)(limit & 0x00ff0000) << 32) |       \
+        ((uint64_t)(base & 0x00ffff00) << 16) |        \
+        ((uint64_t)(limit & 0x0000ffff)))
+
+static void get_bytes(void *buf, size_t len, struct file_info *finfo,
+                     size_t pos)
+{
+  size_t end;
+  static uint64_t gdt[6];
+  size_t bufl;
+
+  pos += (size_t)finfo->pvt;   /* Add base */
+  end = pos+len;
+
+  if (end <= 0x100000) {
+    /* Can stay in real mode */
+    asm volatile("movw %3,%%fs ; "
+                "fs; rep; movsl ; "
+                "movw %2,%%cx ; "
+                "rep; movsb"
+                : : "D" (buf), "c" (len >> 2), "r" ((uint16_t)(len & 3)),
+                "rm" ((uint16_t)(pos >> 4)), "S" (pos & 15)
+                : "memory");
+  } else {
+    bufl = (ds() << 4)+(size_t)buf;
+    gdt[2] = GDT_ENTRY(0x0093, pos, 0xffff);
+    gdt[3] = GDT_ENTRY(0x0093, bufl, 0xffff);
+    asm volatile("pushal ; int $0x15 ; popal"
+                : : "a" (0x8700), "c" ((len+1) >> 1), "S" (&gdt)
+                : "memory");
+  }
+}
+
+static uint32_t pci_readl(int bus, int devfn, int reg)
+{
+  outl(0x80000000 | (bus << 16) | (devfn << 8) | reg, 0xcf8);
+  return inl(0xcfc);
+}
+
+int main(int argc, char *argv[])
+{
+  uint16_t bios_ports[4];
+  const char *prefix;
+  char filename[1024];
+  int i;
+  static struct serial_if sif =
+    {
+      .read  = serial_read,
+      .write = serial_write,
+    };
+  struct file_info finfo;
+  const char serial_banner[] = "Now being Ymodem download...\r\n";
+
+  puts("Hello, world...\n");
+
+  printf("03:02.00 id  = 0x%08x\n", pci_readl(3,2<<3,0));
+  printf("03:02.00 cmd = 0x%08x\n", pci_readl(3,2<<3,4));
+  printf("03:02.00 bar = 0x%08x\n", pci_readl(3,2<<3,0x10));
+
+  if (argc < 4)
+    die("usage: memdump port prefix start,len...");
+
+  finfo.pvt = (void *)0x400;
+  get_bytes(bios_ports, 8, &finfo, 0); /* Get BIOS serial ports */
+
+  for (i = 0; i < 4; i++)
+    printf("ttyS%i (COM%i) is at %#x\n", i, i+1, bios_ports[i]);
+
+  sif.port = strtoul(argv[1], NULL, 0);
+  if (sif.port <= 3) {
+    sif.port = bios_ports[sif.port];
+  }
+
+  if (serial_init(&sif))
+    die("failed to initialize serial port");
+
+  prefix = argv[2];
+
+  puts("Printing prefix...\n");
+  sif.write(&sif, serial_banner, sizeof serial_banner-1);
+
+  for (i = 3; i < argc; i++) {
+    uint32_t start, len;
+    char *ep;
+
+    start = strtoul(argv[i], &ep, 0);
+    if (*ep != ',')
+      die("invalid range specification");
+    len = strtoul(ep+1, NULL, 0);
+
+    sprintf(filename, "%s%#x,%#x", prefix, start, len);
+    finfo.name = filename;
+    finfo.size = len;
+    finfo.pvt  = (void *)start;
+
+    puts("Sending ");
+    puts(filename);
+    puts("...\n");
+
+    send_ymodem(&sif, &finfo, get_bytes);
+  }
+
+  puts("Sending closing signature...\n");
+  end_ymodem(&sif);
+
+  return 0;
+}
diff --git a/memdump/malloc.h b/memdump/malloc.h
new file mode 100644 (file)
index 0000000..70d0e63
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * This is the minimum chunk size we will ask the kernel for; this should
+ * be a multiple of the page size on all architectures.
+ */
+#define MALLOC_CHUNK_SIZE      65536
+#define MALLOC_CHUNK_MASK       (MALLOC_CHUNK_SIZE-1)
+
+/*
+ * This structure should be a power of two.  This becomes the
+ * alignment unit.
+ */
+struct free_arena_header;
+
+struct arena_header {
+  size_t type;
+  size_t size;                 /* Also gives the location of the next entry */
+  struct free_arena_header *next, *prev;
+};
+
+#ifdef DEBUG_MALLOC
+#define ARENA_TYPE_USED 0x64e69c70
+#define ARENA_TYPE_FREE 0x012d610a
+#define ARENA_TYPE_HEAD 0x971676b5
+#define ARENA_TYPE_DEAD 0xeeeeeeee
+#else
+#define ARENA_TYPE_USED 0
+#define ARENA_TYPE_FREE 1
+#define ARENA_TYPE_HEAD 2
+#endif
+
+#define ARENA_SIZE_MASK (sizeof(struct arena_header)-1)
+
+#define ARENA_ALIGN_UP(p)      ((char *)(((uintptr_t)(p) + ARENA_SIZE_MASK) & ~ARENA_SIZE_MASK))
+#define ARENA_ALIGN_DOWN(p)    ((char *)((uintptr_t)(p) & ~ARENA_SIZE_MASK))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+  struct arena_header a;
+  struct free_arena_header *next_free, *prev_free;
+};
+
+extern struct free_arena_header __malloc_head;
diff --git a/memdump/memcpy.S b/memdump/memcpy.S
new file mode 100644 (file)
index 0000000..76eef73
--- /dev/null
@@ -0,0 +1,23 @@
+#
+# memcpy.S
+#
+# Simple 16-bit memcpy() implementation
+#
+
+       .text
+       .code16gcc
+       .globl memcpy
+       .type memcpy, @function
+memcpy:
+       cld
+       pushw %di
+       pushw %si
+       movw %ax,%di
+       movw %dx,%si
+       # The third argument is already in cx
+       rep ; movsb
+       popw %si
+       popw %di
+       ret
+
+       .size memcpy,.-memcpy
diff --git a/memdump/memset.S b/memdump/memset.S
new file mode 100644 (file)
index 0000000..86e12ab
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# memset.S
+#
+# Minimal 16-bit memset() implementation
+#
+
+       .text
+       .code16gcc
+       .globl memset
+       .type memset, @function
+memset:
+       cld
+       pushw %di
+       movw %ax,%di
+       movb %dl,%al
+       # The third argument is already in %cx
+       rep ; stosb
+       popw %di
+       retl
+
+       .size memset,.-memset
diff --git a/memdump/mystuff.h b/memdump/mystuff.h
new file mode 100644 (file)
index 0000000..7c5ac6f
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef MYSTUFF_H
+#define MYSTUFF_H
+
+#include <stdlib.h>
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+
+unsigned int skip_atou(const char **s);
+unsigned long strtoul(const char *, char **, int);
+
+static inline int
+isdigit(int ch)
+{
+  return (ch >= '0') && (ch <= '9');
+}
+
+#endif /* MYSTUFF_H */
diff --git a/memdump/printf.c b/memdump/printf.c
new file mode 100644 (file)
index 0000000..99b389f
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * 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.  It's therefore GPL.
+ *
+ * printf() isn't actually needed to build syslinux.com, but during
+ * debugging it's handy.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "mystuff.h"
+
+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_atou(&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_atou(&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/memdump/serial.c b/memdump/serial.c
new file mode 100644 (file)
index 0000000..902dcc3
--- /dev/null
@@ -0,0 +1,80 @@
+#include "mystuff.h"
+#include "ymsend.h"
+#include "io.h"
+
+enum {
+  THR = 0,
+  RBR = 0,
+  DLL = 0,
+  DLM = 1,
+  IER = 1,
+  IIR = 2,
+  FCR = 2,
+  LCR = 3,
+  MCR = 4,
+  LSR = 5,
+  MSR = 6,
+  SCR = 7,
+};
+
+int serial_init(struct serial_if *sif)
+{
+  uint16_t port = sif->port;
+  uint8_t dll, dlm, lcr;
+
+  /* Set 115200n81 */
+  outb(0x83, port+LCR);
+  outb(0x01, port+DLL);
+  outb(0x00, port+DLM);
+  (void)inb(port+IER);         /* Synchronize */
+  dll = inb(port+DLL);
+  dlm = inb(port+DLM);
+  lcr = inb(port+LCR);
+  outb(0x03, port+LCR);
+  (void)inb(port+IER);         /* Synchronize */
+
+  if (dll != 0x01 || dlm != 0x00 || lcr != 0x83)
+    return -1;                 /* This doesn't look like a serial port */
+
+  /* Disable interrupts */
+  outb(port+IER, 0);
+
+  /* Enable 16550A FIFOs if available */
+  outb(port+FCR, 0x01);                /* Enable FIFO */
+  (void)inb(port+IER);         /* Synchronize */
+  if (inb(port+IIR) < 0xc0)
+    outb(port+FCR, 0x00);      /* Disable FIFOs if non-functional */
+  (void)inb(port+IER);         /* Synchronize */
+
+  return 0;
+}
+
+void serial_write(struct serial_if *sif, const void *data, size_t n)
+{
+  uint16_t port = sif->port;
+  const char *p = data;
+  uint8_t lsr;
+
+  while (n--) {
+    do {
+      lsr = inb(port+LSR);
+    } while (!(lsr & 0x20));
+
+    outb(*p++, port+THR);
+  }
+}
+
+void serial_read(struct serial_if *sif, void *data, size_t n)
+{
+  uint16_t port = sif->port;
+  char *p = data;
+  uint8_t lsr;
+
+  while (n--) {
+    do {
+      lsr = inb(port+LSR);
+    } while (!(lsr & 0x01));
+
+    *p++ = inb(port+RBR);
+  }
+}
diff --git a/memdump/skipatou.c b/memdump/skipatou.c
new file mode 100644 (file)
index 0000000..f71c534
--- /dev/null
@@ -0,0 +1,10 @@
+#include "mystuff.h"
+
+unsigned int skip_atou(const char **s)
+{
+  int i=0;
+
+  while (isdigit(**s))
+    i = i*10 + *((*s)++) - '0';
+  return i;
+}
diff --git a/memdump/stdio.h b/memdump/stdio.h
new file mode 100644 (file)
index 0000000..97988c2
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef STDIO_H
+#define STDIO_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+typedef unsigned int off_t;
+
+int putchar(int);
+int puts(const char *);
+int sprintf(char * buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int printf(const char *fmt, ...);
+
+#define stdin  0
+#define stdout 1
+#define stderr 2
+
+#define fprintf(x, y, ...) printf(y, ## __VA_ARGS__)
+
+#endif /* STDIO_H */
diff --git a/memdump/stdlib.h b/memdump/stdlib.h
new file mode 100644 (file)
index 0000000..6ead86a
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+#define NULL ((void *)0)
+
+typedef int ssize_t;
+typedef unsigned int size_t;
+
+void __attribute__((noreturn)) exit(int);
+
+void *malloc(size_t);
+void free(void *);
+
+#endif
diff --git a/memdump/string.h b/memdump/string.h
new file mode 100644 (file)
index 0000000..44f77da
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * string.h
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+/* Standard routines */
+#define memcpy(a,b,c)  __builtin_memcpy(a,b,c)
+#define memset(a,b,c)  __builtin_memset(a,b,c)
+#define strcpy(a,b)    __builtin_strcpy(a,b)
+#define strlen(a)      __builtin_strlen(a)
+
+/* This only returns true or false */
+static inline int memcmp(const void *__m1, const void *__m2, unsigned int __n)
+{
+  _Bool rv;
+  asm volatile("cld ; repe ; cmpsb ; setne %0"
+              : "=abd" (rv), "+D" (__m1), "+S" (__m2), "+c" (__n));
+  return rv;
+}
+
+#endif /* _STRING_H */
diff --git a/memdump/strtoul.c b/memdump/strtoul.c
new file mode 100644 (file)
index 0000000..cd09d3d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * strtoul.c
+ *
+ */
+
+#include "mystuff.h"
+
+static inline int isspace(int c)
+{
+       return (c <= ' ');      /* Close enough */
+}
+
+static inline int digitval(int ch)
+{
+       if (ch >= '0' && ch <= '9') {
+               return ch - '0';
+       } else if (ch >= 'A' && ch <= 'Z') {
+               return ch - 'A' + 10;
+       } else if (ch >= 'a' && ch <= 'z') {
+               return ch - 'a' + 10;
+       } else {
+               return -1;
+       }
+}
+
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+       int minus = 0;
+       unsigned long v = 0;
+       int d;
+
+       while (isspace((unsigned char)*nptr)) {
+               nptr++;
+       }
+
+       /* Single optional + or - */
+       {
+               char c = *nptr;
+               if (c == '-' || c == '+') {
+                       minus = (c == '-');
+                       nptr++;
+               }
+       }
+
+       if (base == 0) {
+               if (nptr[0] == '0' &&
+                   (nptr[1] == 'x' || nptr[1] == 'X')) {
+                       nptr += 2;
+                       base = 16;
+               } else if (nptr[0] == '0') {
+                       nptr++;
+                       base = 8;
+               } else {
+                       base = 10;
+               }
+       } else if (base == 16) {
+               if (nptr[0] == '0' &&
+                   (nptr[1] == 'x' || nptr[1] == 'X')) {
+                       nptr += 2;
+               }
+       }
+
+       while ((d = digitval(*nptr)) >= 0 && d < base) {
+               v = v * base + d;
+               nptr++;
+       }
+
+       if (endptr)
+               *endptr = (char *)nptr;
+
+       return minus ? -v : v;
+}
diff --git a/memdump/ymodem.txt b/memdump/ymodem.txt
new file mode 100644 (file)
index 0000000..24a6578
--- /dev/null
@@ -0,0 +1,2112 @@
+
+
+
+                                      - 1 -
+
+
+
+                         XMODEM/YMODEM PROTOCOL REFERENCE
+                     A compendium of documents describing the
+
+                                XMODEM and YMODEM
+
+                             File Transfer Protocols
+
+
+
+
+                      This document was formatted 10-14-88.
+
+
+
+
+
+
+
+                             Edited by Chuck Forsberg
+
+
+
+
+
+
+
+
+
+                This file may be redistributed without restriction
+                        provided the text is not altered.
+
+                     Please distribute as widely as possible.
+
+                           Questions to Chuck Forsberg
+
+
+
+
+
+                               Omen Technology Inc
+                          The High Reliability Software
+                            17505-V Sauvie Island Road
+                              Portland Oregon 97231
+                            VOICE: 503-621-3406 :VOICE
+      TeleGodzilla BBS: 503-621-3746 Speed 19200(Telebit PEP),2400,1200,300
+                              CompuServe: 70007,2304
+                                    GEnie: CAF
+                        UUCP: ...!tektronix!reed!omen!caf
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                      - 2 -
+
+
+
+    1.  TOWER OF BABEL
+
+    A "YMODEM Tower of Babel" has descended on the microcomputing community
+    bringing with it confusion, frustration, bloated phone bills, and wasted
+    man hours.  Sadly, I (Chuck Forsberg) am partly to blame for this mess.
+
+    As author of the early 1980s batch and 1k XMODEM extensions, I assumed
+    readers of earlier versions of this document would implement as much of
+    the YMODEM protocol as their programming skills and computing environments
+    would permit.  This proved a rather naive assumption as programmers
+    motivated by competitive pressure implemented as little of YMODEM as
+    possible.  Some have taken whatever parts of YMODEM that appealed to them,
+    applied them to MODEM7 Batch, Telink, XMODEM or whatever, and called the
+    result YMODEM.
+
+    Jeff Garbers (Crosstalk package development director) said it all: "With
+    protocols in the public domain, anyone who wants to dink around with them
+    can go ahead." [1]
+
+    Documents containing altered examples derived from YMODEM.DOC have added
+    to the confusion.  In one instance, some self styled rewriter of history
+    altered the heading in YMODEM.DOC's Figure 1 from "1024 byte Packets" to
+    "YMODEM/CRC File Transfer Protocol".  None of the XMODEM and YMODEM
+    examples shown in that document were correct.
+
+    To put an end to this confusion, we must make "perfectly clear" what
+    YMODEM stands for, as Ward Christensen defined it in his 1985 coining of
+    the term.
+
+    To the majority of you who read, understood, and respected Ward's
+    definition of YMODEM, I apologize for the inconvenience.
+
+    1.1  Definitions
+
+    ARC     ARC is a program that compresses one or more files into an archive
+            and extracts files from such archives.
+
+    XMODEM  refers to the file transfer etiquette introduced by Ward
+            Christensen's 1977 MODEM.ASM program.  The name XMODEM comes from
+            Keith Petersen's XMODEM.ASM program, an adaptation of MODEM.ASM
+            for Remote CP/M (RCPM) systems.  It's also called the MODEM or
+            MODEM2 protocol.  Some who are unaware of MODEM7's unusual batch
+            file mode call it MODEM7.  Other aliases include "CP/M Users'
+            Group" and "TERM II FTP 3".  The name XMODEM caught on partly
+            because it is distinctive and partly because of media interest in
+
+
+    __________
+
+     1. Page C/12, PC-WEEK July 12, 1987
+
+
+
+
+    Chapter 1
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              3
+
+
+
+            bulletin board and RCPM systems where it was accessed with an
+            "XMODEM" command.  This protocol is supported by every serious
+            communications program because of its universality, simplicity,
+            and reasonable performance.
+
+    XMODEM/CRC replaces XMODEM's 1 byte checksum with a two byte Cyclical
+            Redundancy Check (CRC-16), giving modern error detection
+            protection.
+
+    XMODEM-1k Refers to the XMODEM/CRC protocol with 1024 byte data blocks.
+
+    YMODEM  Refers to the XMODEM/CRC (optional 1k blocks) protocol with batch
+            transmission as described below.  In a nutshell, YMODEM means
+            BATCH.
+
+    YMODEM-g Refers to the streaming YMODEM variation described below.
+
+    True YMODEM(TM) In an attempt to sort out the YMODEM Tower of Babel, Omen
+            Technology has trademarked the term True YMODEM(TM) to represent
+            the complete YMODEM protocol described in this document, including
+            pathname, length, and modification date transmitted in block 0.
+            Please contact Omen Technology about certifying programs for True
+            YMODEM(TM) compliance.
+
+    ZMODEM  uses familiar XMODEM/CRC and YMODEM technology in a new protocol
+            that provides reliability, throughput, file management, and user
+            amenities appropriate to contemporary data communications.
+
+    ZOO     Like ARC, ZOO is a program that compresses one or more files into
+            a "zoo archive".  ZOO supports many different operating systems
+            including Unix and VMS.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 1
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              4
+
+
+
+    2.  YMODEM MINIMUM REQUIREMENTS
+
+    All programs claiming to support YMODEM must meet the following minimum
+    requirements:
+
+       + The sending program shall send the pathname (file name) in block 0.
+
+       + The pathname shall be a null terminated ASCII string as described
+         below.
+
+         For those who are too lazy to read the entire document:
+
+            + Unless specifically requested, only the file name portion is
+              sent.
+
+            + No drive letter is sent.
+
+            + Systems that do not distinguish between upper and lower case
+              letters in filenames shall send the pathname in lower case only.
+
+
+       + The receiving program shall use this pathname for the received file
+         name, unless explicitly overridden.
+
+       + When the receiving program receives this block and successfully
+         opened the output file, it shall acknowledge this block with an ACK
+         character and then proceed with a normal XMODEM file transfer
+         beginning with a "C" or NAK tranmsitted by the receiver.
+
+       + The sending program shall use CRC-16 in response to a "C" pathname
+         nak, otherwise use 8 bit checksum.
+
+       + The receiving program must accept any mixture of 128 and 1024 byte
+         blocks within each file it receives.  Sending programs may
+         arbitrarily switch between 1024 and 128 byte blocks.
+
+       + The sending program must not change the length of an unacknowledged
+         block.
+
+       + At the end of each file, the sending program shall send EOT up to ten
+         times until it receives an ACK character.  (This is part of the
+         XMODEM spec.)
+
+       + The end of a transfer session shall be signified by a null (empty)
+         pathname, this pathname block shall be acknowledged the same as other
+         pathname blocks.
+
+    Programs not meeting all of these requirements are not YMODEM compatible,
+    and shall not be described as supporting YMODEM.
+
+    Meeting these MINIMUM requirements does not guarantee reliable file
+
+
+
+    Chapter 2
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              5
+
+
+
+    transfers under stress.  Particular attention is called to XMODEM's single
+    character supervisory messages that are easily corrupted by transmission
+    errors.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 2
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              6
+
+
+
+    3.  WHY YMODEM?
+
+    Since its development half a decade ago, the Ward Christensen modem
+    protocol has enabled a wide variety of computer systems to interchange
+    data.  There is hardly a communications program that doesn't at least
+    claim to support this protocol.
+
+    Advances in computing, modems and networking have revealed a number of
+    weaknesses in the original protocol:
+
+       + The short block length caused throughput to suffer when used with
+         timesharing systems, packet switched networks, satellite circuits,
+         and buffered (error correcting) modems.
+
+       + The 8 bit arithmetic checksum and other aspects allowed line
+         impairments to interfere with dependable, accurate transfers.
+
+       + Only one file could be sent per command.  The file name had to be
+         given twice, first to the sending program and then again to the
+         receiving program.
+
+       + The transmitted file could accumulate as many as 127 extraneous
+         bytes.
+
+       + The modification date of the file was lost.
+
+    A number of other protocols have been developed over the years, but none
+    have displaced XMODEM to date:
+
+       + Lack of public domain documentation and example programs have kept
+         proprietary protocols such as Blast, Relay, and others tightly bound
+         to the fortunes of their suppliers.
+
+       + Complexity discourages the widespread application of BISYNC, SDLC,
+         HDLC, X.25, and X.PC protocols.
+
+       + Performance compromises and complexity have limited the popularity of
+         the Kermit protocol, which was developed to allow file transfers in
+         environments hostile to XMODEM.
+
+    The XMODEM protocol extensions and YMODEM Batch address some of these
+    weaknesses while maintaining most of XMODEM's simplicity.
+
+    YMODEM is supported by the public domain programs YAM (CP/M),
+    YAM(CP/M-86), YAM(CCPM-86), IMP (CP/M), KMD (CP/M), rz/sz (Unix, Xenix,
+    VMS, Berkeley Unix, Venix, Xenix, Coherent, IDRIS, Regulus).  Commercial
+    implementations include MIRROR, and Professional-YAM.[1] Communications
+
+
+
+
+
+
+
+    Chapter 3
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              7
+
+
+
+    programs supporting these extensions have been in use since 1981.
+
+    The 1k block length (XMODEM-1k) described below may be used in conjunction
+    with YMODEM Batch Protocol, or with single file transfers identical to the
+    XMODEM/CRC protocol except for minimal changes to support 1k blocks.
+
+    Another extension is the YMODEM-g protocol.  YMODEM-g provides batch
+    transfers with maximum throughput when used with end to end error
+    correcting media, such as X.PC and error correcting modems, including 9600
+    bps units by TeleBit, U.S.Robotics, Hayes, Electronic Vaults, Data Race,
+    and others.
+
+    To complete this tome, edited versions of Ward Christensen's original
+    protocol document and John Byrns's CRC-16 document are included for
+    reference.
+
+    References to the MODEM or MODEM7 protocol have been changed to XMODEM to
+    accommodate the vernacular.  In Australia, it is properly called the
+    Christensen Protocol.
+
+
+    3.1  Some Messages from the Pioneer
+
+    #: 130940 S0/Communications 25-Apr-85  18:38:47
+    Sb: my protocol
+    Fm: Ward Christensen 76703,302 [2]
+    To: all
+
+    Be aware the article[3] DID quote me correctly in terms of the phrases
+    like "not robust", etc.
+
+    It was a quick hack I threw together, very unplanned (like everything I
+    do), to satisfy a personal need to communicate with "some other" people.
+
+    ONLY the fact that it was done in 8/77, and that I put it in the public
+    domain immediately, made it become the standard that it is.
+
+
+
+
+
+
+
+    __________________________________________________________________________
+
+     1. Available for IBM PC,XT,AT, Unix and Xenix
+
+     2. Edited for typesetting appearance
+
+     3. Infoworld April 29 p. 16
+
+
+
+
+    Chapter 3
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              8
+
+
+
+    I think its time for me to
+
+    (1) document it; (people call me and say "my product is going to include
+    it - what can I 'reference'", or "I'm writing a paper on it, what do I put
+    in the bibliography") and
+
+    (2) propose an "incremental extension" to it, which might take "exactly"
+    the form of Chuck Forsberg's YAM protocol.  He wrote YAM in C for CP/M and
+    put it in the public domain, and wrote a batch protocol for Unix[4] called
+    rb and sb (receive batch, send batch), which was basically XMODEM with
+       (a) a record 0 containing filename date time and size
+       (b) a 1K block size option
+       (c) CRC-16.
+
+    He did some clever programming to detect false ACK or EOT, but basically
+    left them the same.
+
+    People who suggest I make SIGNIFICANT changes to the protocol, such as
+    "full duplex", "multiple outstanding blocks", "multiple destinations", etc
+    etc don't understand that the incredible simplicity of the protocol is one
+    of the reasons it survived to this day in as many machines and programs as
+    it may be found in!
+
+    Consider the PC-NET group back in '77 or so - documenting to beat the band
+    - THEY had a protocol, but it was "extremely complex", because it tried to
+    be "all things to all people" - i.e. send binary files on a 7-bit system,
+    etc.  I was not that "benevolent". I (emphasize > I < ) had an 8-bit UART,
+    so "my protocol was an 8-bit protocol", and I would just say "sorry" to
+    people who were held back by 7-bit limitations.  ...
+
+    Block size: Chuck Forsberg created an extension of my protocol, called
+    YAM, which is also supported via his public domain programs for UNIX
+    called rb and sb - receive batch and send batch.  They cleverly send a
+    "block 0" which contains the filename, date, time, and size.
+    Unfortunately, its UNIX style, and is a bit weird[5] - octal numbers, etc.
+    BUT, it is a nice way to overcome the kludgy "echo the chars of the name"
+    introduced with MODEM7.  Further, chuck uses CRC-16 and optional 1K
+    blocks.  Thus the record 0, 1K, and CRC, make it a "pretty slick new
+    protocol" which is not significantly different from my own.
+
+    Also, there is a catchy name - YMODEM.  That means to some that it is the
+    "next thing after XMODEM", and to others that it is the Y(am)MODEM
+
+
+    __________
+
+     4. VAX/VMS versions of these programs are also available.
+
+     5. The file length, time, and file mode are optional.  The pathname and
+        file length may be sent alone if desired.
+
+
+
+
+    Chapter 3
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                              9
+
+
+
+    protocol.  I don't want to emphasize that too much - out of fear that
+    other mfgrs might think it is a "competitive" protocol, rather than an
+    "unaffiliated" protocol.  Chuck is currently selling a much-enhanced
+    version of his CP/M-80 C program YAM, calling it Professional Yam, and its
+    for the PC - I'm using it right now.  VERY slick!  32K capture buffer,
+    script, scrolling, previously captured text search, plus built-in commands
+    for just about everything - directory (sorted every which way), XMODEM,
+    YMODEM, KERMIT, and ASCII file upload/download, etc.  You can program it
+    to "behave" with most any system - for example when trying a number for
+    CIS it detects the "busy" string back from the modem and substitutes a
+    diff phone # into the dialing string and branches back to try it.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 3
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             10
+
+
+
+    4.  XMODEM PROTOCOL ENHANCEMENTS
+
+    This chapter discusses the protocol extensions to Ward Christensen's 1982
+    XMODEM protocol description document.
+
+    The original document recommends the user be asked whether to continue
+    trying or abort after 10 retries.  Most programs no longer ask the
+    operator whether he wishes to keep retrying.  Virtually all correctable
+    errors are corrected within the first few retransmissions.  If the line is
+    so bad that ten attempts are insufficient, there is a significant danger
+    of undetected errors.  If the connection is that bad, it's better to
+    redial for a better connection, or mail a floppy disk.
+
+
+    4.1  Graceful Abort
+
+    The YAM and Professional-YAM X/YMODEM routines recognize a sequence of two
+    consecutive CAN (Hex 18) characters without modem errors (overrun,
+    framing, etc.) as a transfer abort command.  This sequence is recognized
+    when is waiting for the beginning of a block or for an acknowledgement to
+    a block that has been sent.  The check for two consecutive CAN characters
+    reduces the number of transfers aborted by line hits.  YAM sends eight CAN
+    characters when it aborts an XMODEM, YMODEM, or ZMODEM protocol file
+    transfer.  Pro-YAM then sends eight backspaces to delete the CAN
+    characters from the remote's keyboard input buffer, in case the remote had
+    already aborted the transfer and was awaiting a keyboarded command.
+
+
+    4.2  CRC-16 Option
+
+    The XMODEM protocol uses an optional two character CRC-16 instead of the
+    one character arithmetic checksum used by the original protocol and by
+    most commercial implementations.  CRC-16 guarantees detection of all
+    single and double bit errors,  all errors with an odd number of error
+    bits, all burst errors of length 16 or less, 99.9969% of all 17-bit error
+    bursts, and 99.9984 per cent of all possible longer error bursts.  By
+    contrast, a double bit error, or a burst error of 9 bits or more can sneak
+    past the XMODEM protocol arithmetic checksum.
+
+    The XMODEM/CRC protocol is similar to the XMODEM protocol, except that the
+    receiver specifies CRC-16 by sending C (Hex 43) instead of NAK when
+    requesting the FIRST block.  A two byte CRC is sent in place of the one
+    byte arithmetic checksum.
+
+    YAM's c option to the r command enables CRC-16 in single file reception,
+    corresponding to the original implementation in the MODEM7 series
+    programs.  This remains the default because many commercial communications
+    programs and bulletin board systems still do not support CRC-16,
+    especially those written in Basic or Pascal.
+
+    XMODEM protocol with CRC is accurate provided both sender and receiver
+
+
+
+    Chapter 4                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             11
+
+
+
+    both report a successful transmission.  The protocol is robust in the
+    presence of characters lost by buffer overloading on timesharing systems.
+
+    The single character ACK/NAK responses generated by the receiving program
+    adapt well to split speed modems, where the reverse channel is limited to
+    ten per cent or less of the main channel's speed.
+
+    XMODEM and YMODEM are half duplex protocols which do not attempt to
+    transmit information and control signals in both directions at the same
+    time.  This avoids buffer overrun problems that have been reported by
+    users attempting to exploit full duplex asynchronous file transfer
+    protocols such as Blast.
+
+    Professional-YAM adds several proprietary logic enhancements to XMODEM's
+    error detection and recovery.  These compatible enhancements eliminate
+    most of the bad file transfers other programs make when using the XMODEM
+    protocol under less than ideal conditions.
+
+
+    4.3  XMODEM-1k 1024 Byte Block
+
+    Disappointing throughput downloading from Unix with YMODEM[1] lead to the
+    development of 1024 byte blocks in 1982.  1024 byte blocks reduce the
+    effect of delays from timesharing systems, modems, and packet switched
+    networks on throughput by 87.5 per cent in addition to decreasing XMODEM's
+    3 per cent overhead (block number, CRC, etc.).
+
+    Some environments cannot accept 1024 byte bursts, including some networks
+    and minicomputer ports.  The longer block length should be an option.
+
+    The choice to use 1024 byte blocks is expressed to the sending program on
+    its command line or selection menu.[2] 1024 byte blocks improve throughput
+    in many applications.
+
+    An STX (02) replaces the SOH (01) at the beginning of the transmitted
+    block to notify the receiver of the longer block length.  The transmitted
+    block contains 1024 bytes of data.  The receiver should be able to accept
+    any mixture of 128 and 1024 byte blocks.  The block number (in the second
+    and third bytes of the block) is incremented by one for each block
+    regardless of the block length.
+
+    The sender must not change between 128 and 1024 byte block lengths if it
+    has not received a valid ACK for the current block.  Failure to observe
+
+
+    __________
+
+     1. The name hadn't been coined yet, but the protocol was the same.
+
+     2. See "KMD/IMP Exceptions to YMODEM" below.
+
+
+
+
+    Chapter 4                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             12
+
+
+
+    this restriction allows transmission errors to pass undetected.
+
+    If 1024 byte blocks are being used, it is possible for a file to "grow" up
+    to the next multiple of 1024 bytes.  This does not waste disk space if the
+    allocation granularity is 1k or greater.  With YMODEM batch transmission,
+    the optional file length transmitted in the file name block allows the
+    receiver to discard the padding, preserving the exact file length and
+    contents.
+
+    1024 byte blocks may be used with batch file transmission or with single
+    file transmission.  CRC-16 should be used with the k option to preserve
+    data integrity over phone lines.  If a program wishes to enforce this
+    recommendation, it should cancel the transfer, then issue an informative
+    diagnostic message if the receiver requests checksum instead of CRC-16.
+
+    Under no circumstances may a sending program use CRC-16 unless the
+    receiver commands CRC-16.
+
+             Figure 1.  XMODEM-1k Blocks
+
+             SENDER                                  RECEIVER
+                                                     "sx -k foo.bar"
+             "foo.bar open x.x minutes"
+                                                     C
+             STX 01 FE Data[1024] CRC CRC
+                                                     ACK
+             STX 02 FD Data[1024] CRC CRC
+                                                     ACK
+             STX 03 FC Data[1000] CPMEOF[24] CRC CRC
+                                                     ACK
+             EOT
+                                                     ACK
+
+             Figure 2.  Mixed 1024 and 128 byte Blocks
+
+             SENDER                                  RECEIVER
+                                                     "sx -k foo.bar"
+             "foo.bar open x.x minutes"
+                                                     C
+             STX 01 FE Data[1024] CRC CRC
+                                                     ACK
+             STX 02 FD Data[1024] CRC CRC
+                                                     ACK
+             SOH 03 FC Data[128] CRC CRC
+                                                     ACK
+             SOH 04 FB Data[100] CPMEOF[28] CRC CRC
+                                                     ACK
+             EOT
+                                                     ACK
+
+
+
+
+
+    Chapter 4                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             13
+
+
+
+    5.  YMODEM Batch File Transmission
+
+    The YMODEM Batch protocol is an extension to the XMODEM/CRC protocol that
+    allows 0 or more files to be transmitted with a single command.  (Zero
+    files may be sent if none of the requested files is accessible.) The
+    design approach of the YMODEM Batch protocol is to use the normal routines
+    for sending and receiving XMODEM blocks in a layered fashion similar to
+    packet switching methods.
+
+    Why was it necessary to design a new batch protocol when one already
+    existed in MODEM7?[1] The batch file mode used by MODEM7 is unsuitable
+    because it does not permit full pathnames, file length, file date, or
+    other attribute information to be transmitted.  Such a restrictive design,
+    hastily implemented with only CP/M in mind, would not have permitted
+    extensions to current areas of personal computing such as Unix, DOS, and
+    object oriented systems.  In addition, the MODEM7 batch file mode is
+    somewhat susceptible to transmission impairments.
+
+    As in the case of single a file transfer, the receiver initiates batch
+    file transmission by sending a "C" character (for CRC-16).
+
+    The sender opens the first file and sends block number 0 with the
+    following information.[2]
+
+    Only the pathname (file name) part is required for batch transfers.
+
+    To maintain upwards compatibility, all unused bytes in block 0 must be set
+    to null.
+
+    Pathname The pathname (conventionally, the file name) is sent as a null
+         terminated ASCII string.  This is the filename format used by the
+         handle oriented MSDOS(TM) functions and C library fopen functions.
+         An assembly language example follows:
+                                  DB      'foo.bar',0
+         No spaces are included in the pathname.  Normally only the file name
+         stem (no directory prefix) is transmitted unless the sender has
+         selected YAM's f option to send the full pathname.  The source drive
+         (A:, B:, etc.) is not sent.
+
+         Filename Considerations:
+
+
+
+    __________
+
+     1. The MODEM7 batch protocol transmitted CP/M FCB bytes f1...f8 and
+        t1...t3 one character at a time.  The receiver echoed these bytes as
+        received, one at a time.
+
+     2. Only the data part of the block is described here.
+
+
+
+
+    Chapter 5                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             14
+
+
+
+            + File names are forced to lower case unless the sending system
+              supports upper/lower case file names.  This is a convenience for
+              users of systems (such as Unix) which store filenames in upper
+              and lower case.
+
+            + The receiver should accommodate file names in lower and upper
+              case.
+
+            + When transmitting files between different operating systems,
+              file names must be acceptable to both the sender and receiving
+              operating systems.
+
+         If directories are included, they are delimited by /; i.e.,
+         "subdir/foo" is acceptable, "subdir\foo" is not.
+
+    Length The file length and each of the succeeding fields are optional.[3]
+         The length field is stored in the block as a decimal string counting
+         the number of data bytes in the file.  The file length does not
+         include any CPMEOF (^Z) or other garbage characters used to pad the
+         last block.
+
+         If the file being transmitted is growing during transmission, the
+         length field should be set to at least the final expected file
+         length, or not sent.
+
+         The receiver stores the specified number of characters, discarding
+         any padding added by the sender to fill up the last block.
+
+    Modification Date The mod date is optional, and the filename and length
+         may be sent without requiring the mod date to be sent.
+
+         Iff the modification date is sent, a single space separates the
+         modification date from the file length.
+
+         The mod date is sent as an octal number giving the time the contents
+         of the file were last changed, measured in seconds from Jan 1 1970
+         Universal Coordinated Time (GMT).  A date of 0 implies the
+         modification date is unknown and should be left as the date the file
+         is received.
+
+         This standard format was chosen to eliminate ambiguities arising from
+         transfers between different time zones.
+
+
+
+
+
+    __________
+
+     3. Fields may not be skipped.
+
+
+
+
+    Chapter 5                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             15
+
+
+
+    Mode Iff the file mode is sent, a single space separates the file mode
+         from the modification date.  The file mode is stored as an octal
+         string.  Unless the file originated from a Unix system, the file mode
+         is set to 0.  rb(1) checks the file mode for the 0x8000 bit which
+         indicates a Unix type regular file.  Files with the 0x8000 bit set
+         are assumed to have been sent from another Unix (or similar) system
+         which uses the same file conventions.  Such files are not translated
+         in any way.
+
+
+    Serial Number Iff the serial number is sent, a single space separates the
+         serial number from the file mode.  The serial number of the
+         transmitting program is stored as an octal string.  Programs which do
+         not have a serial number should omit this field, or set it to 0.  The
+         receiver's use of this field is optional.
+
+
+    Other Fields YMODEM was designed to allow additional header fields to be
+         added as above without creating compatibility problems with older
+         YMODEM programs.  Please contact Omen Technology if other fields are
+         needed for special application requirements.
+
+    The rest of the block is set to nulls.  This is essential to preserve
+    upward compatibility.[4]
+
+    If the filename block is received with a CRC or other error, a
+    retransmission is requested.  After the filename block has been received,
+    it is ACK'ed if the write open is successful.  If the file cannot be
+    opened for writing, the receiver cancels the transfer with CAN characters
+    as described above.
+
+    The receiver then initiates transfer of the file contents with a "C"
+    character, according to the standard XMODEM/CRC protocol.
+
+    After the file contents and XMODEM EOT have been transmitted and
+    acknowledged, the receiver again asks for the next pathname.
+
+    Transmission of a null pathname terminates batch file transmission.
+
+    Note that transmission of no files is not necessarily an error.  This is
+    possible if none of the files requested of the sender could be opened for
+    reading.
+
+
+
+    __________
+
+     4. If, perchance, this information extends beyond 128 bytes (possible
+        with Unix 4.2 BSD extended file names), the block should be sent as a
+        1k block as described above.
+
+
+
+
+    Chapter 5                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             16
+
+
+
+    Most YMODEM receivers request CRC-16 by default.
+
+    The Unix programs sz(1) and rz(1) included in the source code file
+    RZSZ.ZOO should answer other questions about YMODEM batch protocol.
+
+              Figure 3.  YMODEM Batch Transmission Session (1 file)
+
+              SENDER                                  RECEIVER
+                                                      "sb foo.*<CR>"
+              "sending in batch mode etc."
+                                                      C (command:rb)
+              SOH 00 FF foo.c NUL[123] CRC CRC
+                                                      ACK
+                                                      C
+              SOH 01 FE Data[128] CRC CRC
+                                                      ACK
+              SOH 02 FC Data[128] CRC CRC
+                                                      ACK
+              SOH 03 FB Data[100] CPMEOF[28] CRC CRC
+                                                      ACK
+              EOT
+                                                      NAK
+              EOT
+                                                      ACK
+                                                      C
+              SOH 00 FF NUL[128] CRC CRC
+                                                      ACK
+
+                Figure 7.  YMODEM Header Information and Features
+
+    _____________________________________________________________
+    | Program   | Length | Date | Mode | S/N | 1k-Blk | YMODEM-g |
+    |___________|________|______|______|_____|________|__________|
+    |Unix rz/sz | yes    | yes  | yes  | no  | yes    | sb only  |
+    |___________|________|______|______|_____|________|__________|
+    |VMS rb/sb  | yes    | no   | no   | no  | yes    | no       |
+    |___________|________|______|______|_____|________|__________|
+    |Pro-YAM    | yes    | yes  | no   | yes | yes    | yes      |
+    |___________|________|______|______|_____|________|__________|
+    |CP/M YAM   | no     | no   | no   | no  | yes    | no       |
+    |___________|________|______|______|_____|________|__________|
+    |KMD/IMP    | ?      | no   | no   | no  | yes    | no       |
+    |___________|________|______|______|_____|________|__________|
+
+    5.1  KMD/IMP Exceptions to YMODEM
+
+    KMD and IMP use a "CK" character sequence emitted by the receiver to
+    trigger the use of 1024 byte blocks as an alternative to specifying this
+    option to the sending program.  This two character sequence generally
+    works well on single process micros in direct communication, provided the
+    programs rigorously adhere to all the XMODEM recommendations included
+
+
+
+    Chapter 5                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             17
+
+
+
+           Figure 4.  YMODEM Batch Transmission Session (2 files)
+
+           SENDER                                  RECEIVER
+                                                   "sb foo.c baz.c<CR>"
+           "sending in batch mode etc."
+                                                   C (command:rb)
+           SOH 00 FF foo.c NUL[123] CRC CRC
+                                                   ACK
+                                                   C
+           SOH 01 FE Data[128] CRC CRC
+                                                   ACK
+           SOH 02 FC Data[128] CRC CRC
+                                                   ACK
+           SOH 03 FB Data[100] CPMEOF[28] CRC CRC
+                                                   ACK
+           EOT
+                                                   NAK
+           EOT
+                                                   ACK
+                                                   C
+           SOH 00 FF baz.c NUL[123] CRC CRC
+                                                   ACK
+                                                   C
+           SOH 01 FB Data[100] CPMEOF[28] CRC CRC
+                                                   ACK
+           EOT
+                                                   NAK
+           EOT
+                                                   ACK
+                                                   C
+           SOH 00 FF NUL[128] CRC CRC
+                                                   ACK
+
+            Figure 5.  YMODEM Batch Transmission Session-1k Blocks
+
+            SENDER                                  RECEIVER
+                                                    "sb -k foo.*<CR>"
+            "sending in batch mode etc."
+                                                    C (command:rb)
+            SOH 00 FF foo.c NUL[123] CRC CRC
+                                                    ACK
+                                                    C
+            STX 01 FD Data[1024] CRC CRC
+                                                    ACK
+            SOH 02 FC Data[128] CRC CRC
+                                                    ACK
+            SOH 03 FB Data[100] CPMEOF[28] CRC CRC
+                                                    ACK
+            EOT
+                                                    NAK
+            EOT
+
+
+
+    Chapter 5                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             18
+
+
+
+                                                    ACK
+                                                    C
+            SOH 00 FF NUL[128] CRC CRC
+                                                    ACK
+
+           Figure 6.  YMODEM Filename block transmitted by sz
+
+           -rw-r--r--  6347 Jun 17 1984 20:34 bbcsched.txt
+
+           00 0100FF62 62637363 6865642E 74787400   |...bbcsched.txt.|
+           10 36333437 20333331 34373432 35313320   |6347 3314742513 |
+           20 31303036 34340000 00000000 00000000   |100644..........|
+           30 00000000 00000000 00000000 00000000
+           40 00000000 00000000 00000000 00000000
+           50 00000000 00000000 00000000 00000000
+           60 00000000 00000000 00000000 00000000
+           70 00000000 00000000 00000000 00000000
+           80 000000CA 56
+
+    herein.  Programs with marginal XMODEM implementations do not fare so
+    well.  Timesharing systems and packet switched networks can separate the
+    successive characters, rendering this method unreliable.
+
+    Sending programs may detect the CK sequence if the operating enviornment
+    does not preclude reliable implementation.
+
+    Instead of the standard YMODEM file length in decimal, KMD and IMP
+    transmit the CP/M record count in the last two bytes of the header block.
+
+
+    6.  YMODEM-g File Transmission
+
+    Developing technology is providing phone line data transmission at ever
+    higher speeds using very specialized techniques.  These high speed modems,
+    as well as session protocols such as X.PC, provide high speed, nearly
+    error free communications at the expense of considerably increased delay
+    time.
+
+    This delay time is moderate compared to human interactions, but it
+    cripples the throughput of most error correcting protocols.
+
+    The g option to YMODEM has proven effective under these circumstances.
+    The g option is driven by the receiver, which initiates the batch transfer
+    by transmitting a G instead of C.  When the sender recognizes the G, it
+    bypasses the usual wait for an ACK to each transmitted block, sending
+    succeeding blocks at full speed, subject to XOFF/XON or other flow control
+    exerted by the medium.
+
+    The sender expects an inital G to initiate the transmission of a
+    particular file, and also expects an ACK on the EOT sent at the end of
+    each file.  This synchronization allows the receiver time to open and
+
+
+
+    Chapter 6                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             19
+
+
+
+    close files as necessary.
+
+    If an error is detected in a YMODEM-g transfer, the receiver aborts the
+    transfer with the multiple CAN abort sequence.  The ZMODEM protocol should
+    be used in applications that require both streaming throughput and error
+    recovery.
+
+            Figure 8.  YMODEM-g Transmission Session
+
+            SENDER                                  RECEIVER
+                                                    "sb foo.*<CR>"
+            "sending in batch mode etc..."
+                                                    G (command:rb -g)
+            SOH 00 FF foo.c NUL[123] CRC CRC
+                                                    G
+            SOH 01 FE Data[128] CRC CRC
+            STX 02 FD Data[1024] CRC CRC
+            SOH 03 FC Data[128] CRC CRC
+            SOH 04 FB Data[100] CPMEOF[28] CRC CRC
+            EOT
+                                                    ACK
+                                                    G
+            SOH 00 FF NUL[128] CRC CRC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 6                                     XMODEM Protocol Enhancements
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             20
+
+
+
+    7.  XMODEM PROTOCOL OVERVIEW
+
+    8/9/82 by Ward Christensen.
+
+    I will maintain a master copy of this.  Please pass on changes or
+    suggestions via CBBS/Chicago at (312) 545-8086, CBBS/CPMUG (312) 849-1132
+    or by voice at (312) 849-6279.
+
+    7.1  Definitions
+
+      <soh> 01H
+      <eot> 04H
+      <ack> 06H
+      <nak> 15H
+      <can> 18H
+      <C>   43H
+
+
+    7.2  Transmission Medium Level Protocol
+
+    Asynchronous, 8 data bits, no parity, one stop bit.
+
+    The protocol imposes no restrictions on the contents of the data being
+    transmitted.  No control characters are looked for in the 128-byte data
+    messages.  Absolutely any kind of data may be sent - binary, ASCII, etc.
+    The protocol has not formally been adopted to a 7-bit environment for the
+    transmission of ASCII-only (or unpacked-hex) data , although it could be
+    simply by having both ends agree to AND the protocol-dependent data with
+    7F hex before validating it.  I specifically am referring to the checksum,
+    and the block numbers and their ones- complement.
+
+    Those wishing to maintain compatibility of the CP/M file structure, i.e.
+    to allow modemming ASCII files to or from CP/M systems should follow this
+    data format:
+
+       + ASCII tabs used (09H); tabs set every 8.
+
+       + Lines terminated by CR/LF (0DH 0AH)
+
+       + End-of-file indicated by ^Z, 1AH.  (one or more)
+
+       + Data is variable length, i.e. should be considered a continuous
+         stream of data bytes, broken into 128-byte chunks purely for the
+         purpose of transmission.
+
+       + A CP/M "peculiarity": If the data ends exactly on a 128-byte
+         boundary, i.e. CR in 127, and LF in 128, a subsequent sector
+         containing the ^Z EOF character(s) is optional, but is preferred.
+         Some utilities or user programs still do not handle EOF without ^Zs.
+
+
+
+
+
+    Chapter 7                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             21
+
+
+
+       + The last block sent is no different from others, i.e.  there is no
+         "short block".
+                  Figure 9.  XMODEM Message Block Level Protocol
+
+    Each block of the transfer looks like:
+          <SOH><blk #><255-blk #><--128 data bytes--><cksum>
+    in which:
+    <SOH>         = 01 hex
+    <blk #>       = binary number, starts at 01 increments by 1, and
+                    wraps 0FFH to 00H (not to 01)
+    <255-blk #>   = blk # after going thru 8080 "CMA" instr, i.e.
+                    each bit complemented in the 8-bit block number.
+                    Formally, this is the "ones complement".
+    <cksum>       = the sum of the data bytes only.  Toss any carry.
+
+    7.3  File Level Protocol
+
+    7.3.1  Common_to_Both_Sender_and_Receiver
+    All errors are retried 10 times.  For versions running with an operator
+    (i.e. NOT with XMODEM), a message is typed after 10 errors asking the
+    operator whether to "retry or quit".
+
+    Some versions of the protocol use <can>, ASCII ^X, to cancel transmission.
+    This was never adopted as a standard, as having a single "abort" character
+    makes the transmission susceptible to false termination due to an <ack>
+    <nak> or <soh> being corrupted into a <can> and aborting transmission.
+
+    The protocol may be considered "receiver driven", that is, the sender need
+    not automatically re-transmit, although it does in the current
+    implementations.
+
+
+    7.3.2  Receive_Program_Considerations
+    The receiver has a 10-second timeout.  It sends a <nak> every time it
+    times out.  The receiver's first timeout, which sends a <nak>, signals the
+    transmitter to start.  Optionally, the receiver could send a <nak>
+    immediately, in case the sender was ready.  This would save the initial 10
+    second timeout.  However, the receiver MUST continue to timeout every 10
+    seconds in case the sender wasn't ready.
+
+    Once into a receiving a block, the receiver goes into a one-second timeout
+    for each character and the checksum.  If the receiver wishes to <nak> a
+    block for any reason (invalid header, timeout receiving data), it must
+    wait for the line to clear.  See "programming tips" for ideas
+
+    Synchronizing:  If a valid block number is received, it will be: 1) the
+    expected one, in which case everything is fine; or 2) a repeat of the
+    previously received block.  This should be considered OK, and only
+    indicates that the receivers <ack> got glitched, and the sender re-
+    transmitted; 3) any other block number indicates a fatal loss of
+    synchronization, such as the rare case of the sender getting a line-glitch
+
+
+
+    Chapter 7                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             22
+
+
+
+    that looked like an <ack>.  Abort the transmission, sending a <can>
+
+
+    7.3.3  Sending_program_considerations
+    While waiting for transmission to begin, the sender has only a single very
+    long timeout, say one minute.  In the current protocol, the sender has a
+    10 second timeout before retrying.  I suggest NOT doing this, and letting
+    the protocol be completely receiver-driven.  This will be compatible with
+    existing programs.
+
+    When the sender has no more data, it sends an <eot>, and awaits an <ack>,
+    resending the <eot> if it doesn't get one.  Again, the protocol could be
+    receiver-driven, with the sender only having the high-level 1-minute
+    timeout to abort.
+
+
+    Here is a sample of the data flow, sending a 3-block message.  It includes
+    the two most common line hits - a garbaged block, and an <ack> reply
+    getting garbaged.  <xx> represents the checksum byte.
+
+                  Figure 10.  Data flow including Error Recovery
+
+    SENDER                                  RECEIVER
+                                  times out after 10 seconds,
+                                  <---              <nak>
+    <soh> 01 FE -data- <xx>       --->
+                                  <---              <ack>
+    <soh> 02 FD -data- xx         --->       (data gets line hit)
+                                  <---              <nak>
+    <soh> 02 FD -data- xx         --->
+                                  <---              <ack>
+    <soh> 03 FC -data- xx         --->
+    (ack gets garbaged)           <---              <ack>
+    <soh> 03 FC -data- xx         --->              <ack>
+    <eot>                         --->
+                                  <---       <anything except ack>
+    <eot>                         --->
+                                  <---              <ack>
+    (finished)
+
+    7.4  Programming Tips
+
+       + The character-receive subroutine should be called with a parameter
+         specifying the number of seconds to wait.  The receiver should first
+         call it with a time of 10, then <nak> and try again, 10 times.
+
+         After receiving the <soh>, the receiver should call the character
+         receive subroutine with a 1-second timeout, for the remainder of the
+         message and the <cksum>.  Since they are sent as a continuous stream,
+         timing out of this implies a serious like glitch that caused, say,
+         127 characters to be seen instead of 128.
+
+
+
+    Chapter 7                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             23
+
+
+
+       + When the receiver wishes to <nak>, it should call a "PURGE"
+         subroutine, to wait for the line to clear.  Recall the sender tosses
+         any characters in its UART buffer immediately upon completing sending
+         a block, to ensure no glitches were mis- interpreted.
+
+         The most common technique is for "PURGE" to call the character
+         receive subroutine, specifying a 1-second timeout,[1] and looping
+         back to PURGE until a timeout occurs.  The <nak> is then sent,
+         ensuring the other end will see it.
+
+       + You may wish to add code recommended by John Mahr to your character
+         receive routine - to set an error flag if the UART shows framing
+         error, or overrun.  This will help catch a few more glitches - the
+         most common of which is a hit in the high bits of the byte in two
+         consecutive bytes.  The <cksum> comes out OK since counting in 1-byte
+         produces the same result of adding 80H + 80H as with adding 00H +
+         00H.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    __________
+
+     1. These times should be adjusted for use with timesharing systems.
+
+
+
+
+    Chapter 7                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             24
+
+
+
+    8.  XMODEM/CRC Overview
+
+    Original 1/13/85 by John Byrns -- CRC option.
+
+    Please pass on any reports of errors in this document or suggestions for
+    improvement to me via Ward's/CBBS at (312) 849-1132, or by voice at (312)
+    885-1105.
+
+    The CRC used in the Modem Protocol is an alternate form of block check
+    which provides more robust error detection than the original checksum.
+    Andrew S. Tanenbaum says in his book, Computer Networks, that the CRC-
+    CCITT used by the Modem Protocol will detect all single and double bit
+    errors, all errors with an odd number of bits, all burst errors of length
+    16 or less, 99.997% of 17-bit error bursts, and 99.998% of 18-bit and
+    longer bursts.[1]
+
+    The changes to the Modem Protocol to replace the checksum with the CRC are
+    straight forward. If that were all that we did we would not be able to
+    communicate between a program using the old checksum protocol and one
+    using the new CRC protocol. An initial handshake was added to solve this
+    problem. The handshake allows a receiving program with CRC capability to
+    determine whether the sending program supports the CRC option, and to
+    switch it to CRC mode if it does. This handshake is designed so that it
+    will work properly with programs which implement only the original
+    protocol. A description of this handshake is presented in section 10.
+
+                Figure 11.  Message Block Level Protocol, CRC mode
+
+    Each block of the transfer in CRC mode looks like:
+         <SOH><blk #><255-blk #><--128 data bytes--><CRC hi><CRC lo>
+    in which:
+    <SOH>        = 01 hex
+    <blk #>      = binary number, starts at 01 increments by 1, and
+                   wraps 0FFH to 00H (not to 01)
+    <255-blk #>  = ones complement of blk #.
+    <CRC hi>     = byte containing the 8 hi order coefficients of the CRC.
+    <CRC lo>     = byte containing the 8 lo order coefficients of the CRC.
+
+    8.1  CRC Calculation
+
+    8.1.1  Formal_Definition
+    To calculate the 16 bit CRC the message bits are considered to be the
+    coefficients of a polynomial. This message polynomial is first multiplied
+    by X^16 and then divided by the generator polynomial (X^16 + X^12 + X^5 +
+
+
+    __________
+
+     1. This reliability figure is misleading because XMODEM's critical
+        supervisory functions are not protected by this CRC.
+
+
+
+
+    Chapter 8                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             25
+
+
+
+    1) using modulo two arithmetic. The remainder left after the division is
+    the desired CRC. Since a message block in the Modem Protocol is 128 bytes
+    or 1024 bits, the message polynomial will be of order X^1023. The hi order
+    bit of the first byte of the message block is the coefficient of X^1023 in
+    the message polynomial.  The lo order bit of the last byte of the message
+    block is the coefficient of X^0 in the message polynomial.
+
+               Figure 12.  Example of CRC Calculation written in C
+
+    The following XMODEM crc routine is taken from "rbsb.c".  Please refer to
+    the source code for these programs (contained in RZSZ.ZOO) for usage.  A
+    fast table driven version is also included in this file.
+
+    /* update CRC */
+    unsigned short
+    updcrc(c, crc)
+    register c;
+    register unsigned crc;
+    {
+            register count;
+
+            for (count=8; --count>=0;) {
+                    if (crc & 0x8000) {
+                            crc <<= 1;
+                            crc += (((c<<=1) & 0400)  !=  0);
+                            crc ^= 0x1021;
+                    }
+                    else {
+                            crc <<= 1;
+                            crc += (((c<<=1) & 0400)  !=  0);
+                    }
+            }
+            return crc;
+    }
+
+    8.2  CRC File Level Protocol Changes
+
+    8.2.1  Common_to_Both_Sender_and_Receiver
+    The only change to the File Level Protocol for the CRC option is the
+    initial handshake which is used to determine if both the sending and the
+    receiving programs support the CRC mode. All Modem Programs should support
+    the checksum mode for compatibility with older versions.  A receiving
+    program that wishes to receive in CRC mode implements the mode setting
+    handshake by sending a <C> in place of the initial <nak>.  If the sending
+    program supports CRC mode it will recognize the <C> and will set itself
+    into CRC mode, and respond by sending the first block as if a <nak> had
+    been received. If the sending program does not support CRC mode it will
+    not respond to the <C> at all. After the receiver has sent the <C> it will
+    wait up to 3 seconds for the <soh> that starts the first block. If it
+    receives a <soh> within 3 seconds it will assume the sender supports CRC
+    mode and will proceed with the file exchange in CRC mode. If no <soh> is
+
+
+
+    Chapter 8                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             26
+
+
+
+    received within 3 seconds the receiver will switch to checksum mode, send
+    a <nak>, and proceed in checksum mode. If the receiver wishes to use
+    checksum mode it should send an initial <nak> and the sending program
+    should respond to the <nak> as defined in the original Modem Protocol.
+    After the mode has been set by the initial <C> or <nak> the protocol
+    follows the original Modem Protocol and is identical whether the checksum
+    or CRC is being used.
+
+
+    8.2.2  Receive_Program_Considerations
+    There are at least 4 things that can go wrong with the mode setting
+    handshake.
+
+      1.  the initial <C> can be garbled or lost.
+
+      2.  the initial <soh> can be garbled.
+
+      3.  the initial <C> can be changed to a <nak>.
+
+      4.  the initial <nak> from a receiver which wants to receive in checksum
+          can be changed to a <C>.
+
+    The first problem can be solved if the receiver sends a second <C> after
+    it times out the first time. This process can be repeated several times.
+    It must not be repeated too many times before sending a <nak> and
+    switching to checksum mode or a sending program without CRC support may
+    time out and abort. Repeating the <C> will also fix the second problem if
+    the sending program cooperates by responding as if a <nak> were received
+    instead of ignoring the extra <C>.
+
+    It is possible to fix problems 3 and 4 but probably not worth the trouble
+    since they will occur very infrequently. They could be fixed by switching
+    modes in either the sending or the receiving program after a large number
+    of successive <nak>s. This solution would risk other problems however.
+
+
+    8.2.3  Sending_Program_Considerations
+    The sending program should start in the checksum mode. This will insure
+    compatibility with checksum only receiving programs. Anytime a <C> is
+    received before the first <nak> or <ack> the sending program should set
+    itself into CRC mode and respond as if a <nak> were received. The sender
+    should respond to additional <C>s as if they were <nak>s until the first
+    <ack> is received. This will assist the receiving program in determining
+    the correct mode when the <soh> is lost or garbled. After the first <ack>
+    is received the sending program should ignore <C>s.
+
+
+
+
+
+
+
+
+
+    Chapter 8                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             27
+
+
+
+    8.3  Data Flow Examples with CRC Option
+
+    Here is a data flow example for the case where the receiver requests
+    transmission in the CRC mode but the sender does not support the CRC
+    option. This example also includes various transmission errors.  <xx>
+    represents the checksum byte.
+
+          Figure 13.  Data Flow: Receiver has CRC Option, Sender Doesn't
+
+    SENDER                                        RECEIVER
+                            <---                <C>
+                                    times out after 3 seconds,
+                            <---                <C>
+                                    times out after 3 seconds,
+                            <---                <C>
+                                    times out after 3 seconds,
+                            <---                <C>
+                                    times out after 3 seconds,
+                            <---                <nak>
+    <soh> 01 FE -data- <xx> --->
+                            <---                <ack>
+    <soh> 02 FD -data- <xx> --->        (data gets line hit)
+                            <---                <nak>
+    <soh> 02 FD -data- <xx> --->
+                            <---                <ack>
+    <soh> 03 FC -data- <xx> --->
+       (ack gets garbaged)  <---                <ack>
+                                    times out after 10 seconds,
+                            <---                <nak>
+    <soh> 03 FC -data- <xx> --->
+                            <---                <ack>
+    <eot>                   --->
+                            <---                <ack>
+
+    Here is a data flow example for the case where the receiver requests
+    transmission in the CRC mode and the sender supports the CRC option.  This
+    example also includes various transmission errors.  <xxxx> represents the
+    2 CRC bytes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 8                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             28
+
+
+
+               Figure 14.  Receiver and Sender Both have CRC Option
+
+    SENDER                                       RECEIVER
+                              <---                 <C>
+    <soh> 01 FE -data- <xxxx> --->
+                              <---                 <ack>
+    <soh> 02 FD -data- <xxxx> --->         (data gets line hit)
+                              <---                 <nak>
+    <soh> 02 FD -data- <xxxx> --->
+                              <---                 <ack>
+    <soh> 03 FC -data- <xxxx> --->
+    (ack gets garbaged)       <---                 <ack>
+                                         times out after 10 seconds,
+                              <---                 <nak>
+    <soh> 03 FC -data- <xxxx> --->
+                              <---                 <ack>
+    <eot>                     --->
+                              <---                 <ack>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    Chapter 8                                         Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             29
+
+
+
+    9.  MORE INFORMATION
+
+    Please contact Omen Technology for troff source files and typeset copies
+    of this document.
+
+
+    9.1  TeleGodzilla Bulletin Board
+
+    More information may be obtained by calling TeleGodzilla at 503-621-3746.
+    Speed detection is automatic for 1200, 2400 and 19200(Telebit PEP) bps.
+    TrailBlazer modem users may issue the TeleGodzilla trailblazer command to
+    swith to 19200 bps once they have logged in.
+
+    Interesting files include RZSZ.ZOO (C source code), YZMODEM.ZOO (Official
+    XMODEM, YMODEM, and ZMODEM protocol descriptions), ZCOMMEXE.ARC,
+    ZCOMMDOC.ARC, and ZCOMMHLP.ARC (PC-DOS shareware comm program with XMODEM,
+    True YMODEM(TM), ZMODEM, Kermit Sliding Windows, Telink, MODEM7 Batch,
+    script language, etc.).
+
+
+    9.2  Unix UUCP Access
+
+    UUCP sites can obtain the current version of this file with
+                     uucp omen!/u/caf/public/ymodem.doc /tmp
+    A continually updated list of available files is stored in
+    /usr/spool/uucppublic/FILES.  When retrieving these files with uucp,
+    remember that the destination directory on your system must be writeable
+    by anyone, or the UUCP transfer will fail.
+
+    The following L.sys line calls TeleGodzilla (Pro-YAM in host operation).
+    TeleGodzilla determines the incoming speed automatically.
+
+    In response to "Name Please:" uucico gives the Pro-YAM "link" command as a
+    user name.  The password (Giznoid) controls access to the Xenix system
+    connected to the IBM PC's other serial port.  Communications between
+    Pro-YAM and Xenix use 9600 bps; YAM converts this to the caller's speed.
+
+    Finally, the calling uucico logs in as uucp.
+
+    omen Any ACU 2400 1-503-621-3746 se:--se: link ord: Giznoid in:--in: uucp
+
+
+
+    10.  REVISIONS
+
+    6-18-88 Further revised for clarity.  Corrected block numbering in two
+    examples.
+    10-27-87 Optional fields added for number of files remaining to be sent
+    and total number of bytes remaining to be sent.
+    10-18-87 Flow control discussion added to 1024 byte block descritpion,
+    minor revisions for clarity per user comments.
+
+
+
+    Chapter 10                                        Xmodem Protocol Overview
+
+
+
+
+
+
+
+    X/YMODEM Protocol Reference    June 18 1988                             30
+
+
+
+    8-03-87 Revised for clarity.
+    5-31-1987 emphasizes minimum requirements for YMODEM, and updates
+    information on accessing files.
+    9-11-1986 clarifies nomenclature and some minor points.
+    The April 15 1986 edition clarifies some points concerning CRC
+    calculations and spaces in the header.
+
+
+    11.  YMODEM Programs
+
+    ZCOMM, A shareware little brother to Professional-YAM, is available as
+    ZCOMMEXE.ARC on TeleGodzilla and other bulletin board systems.  ZCOMM may
+    be used to test YMODEM amd ZMODEM implementations.
+
+    Unix programs supporting YMODEM are available on TeleGodzilla in RZSZ.ZOO.
+    This ZOO archive includes a ZCOMM/Pro-YAM/PowerCom script ZUPL.T to upload
+    a bootstrap program MINIRB.C, compile it, and then upload the rest of the
+    files using the compiled MINIRB.  Most Unix like systems are supported,
+    including V7, Xenix, Sys III, 4.2 BSD, SYS V, Idris, Coherent, and
+    Regulus.
+
+    A version for VAX-VMS is available in VRBSB.SHQ.
+
+    Irv Hoff has added 1k blocks and basic YMODEM batch transfers to the KMD
+    and IMP series programs, which replace the XMODEM and MODEM7/MDM7xx series
+    respectively.  Overlays are available for a wide variety of CP/M systems.
+
+    Questions about Professional-YAM communications software may be directed
+    to:
+         Chuck Forsberg
+         Omen Technology Inc
+         17505-V Sauvie Island Road
+         Portland Oregon 97231
+         VOICE: 503-621-3406 :VOICE
+         Modem: 503-621-3746 Speed: 19200(Telebit PEP),2400,1200,300
+         Usenet: ...!tektronix!reed!omen!caf
+         CompuServe: 70007,2304
+         GEnie: CAF
+
+    Unlike ZMODEM and Kermit, XMODEM and YMODEM place obstacles in the path of
+    a reliable high performance implementation, evidenced by poor reliability
+    under stress of the industry leaders' XMODEM and YMODEM programs.  Omen
+    Technology provides consulting and other services to those wishing to
+    implement XMODEM, YMODEM, and ZMODEM with state of the art features and
+    reliability.
+
+
+
+
+
+
+
+
+
+    Chapter 11                                        Xmodem Protocol Overview
+
+
+
+
+
+
+
+
+
+
+
+                                     CONTENTS
+
+
+     1.  TOWER OF BABEL...................................................   2
+         1.1  Definitions.................................................   2
+
+     2.  YMODEM MINIMUM REQUIREMENTS......................................   4
+
+     3.  WHY YMODEM?......................................................   6
+         3.1  Some Messages from the Pioneer..............................   7
+
+     4.  XMODEM PROTOCOL ENHANCEMENTS.....................................  10
+         4.1  Graceful Abort..............................................  10
+         4.2  CRC-16 Option...............................................  10
+         4.3  XMODEM-1k 1024 Byte Block...................................  11
+
+     5.  YMODEM Batch File Transmission...................................  13
+         5.1  KMD/IMP Exceptions to YMODEM................................  16
+
+     6.  YMODEM-g File Transmission.......................................  18
+
+     7.  XMODEM PROTOCOL OVERVIEW.........................................  20
+         7.1  Definitions.................................................  20
+         7.2  Transmission Medium Level Protocol..........................  20
+         7.3  File Level Protocol.........................................  21
+         7.4  Programming Tips............................................  22
+
+     8.  XMODEM/CRC Overview..............................................  24
+         8.1  CRC Calculation.............................................  24
+         8.2  CRC File Level Protocol Changes.............................  25
+         8.3  Data Flow Examples with CRC Option..........................  27
+
+     9.  MORE INFORMATION.................................................  29
+         9.1  TeleGodzilla Bulletin Board.................................  29
+         9.2  Unix UUCP Access............................................  29
+
+    10.  REVISIONS........................................................  29
+
+    11.  YMODEM Programs..................................................  30
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                      - i -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                 LIST OF FIGURES
+
+
+     Figure 1.  XMODEM-1k Blocks..........................................  12
+
+     Figure 2.  Mixed 1024 and 128 byte Blocks............................  12
+
+     Figure 3.  YMODEM Batch Transmission Session (1 file)................  16
+
+     Figure 4.  YMODEM Batch Transmission Session (2 files)...............  16
+
+     Figure 5.  YMODEM Batch Transmission Session-1k Blocks...............  16
+
+     Figure 6.  YMODEM Filename block transmitted by sz...................  16
+
+     Figure 7.  YMODEM Header Information and Features....................  16
+
+     Figure 8.  YMODEM-g Transmission Session.............................  19
+
+     Figure 9.  XMODEM Message Block Level Protocol.......................  21
+
+    Figure 10.  Data flow including Error Recovery........................  22
+
+    Figure 11.  Message Block Level Protocol, CRC mode....................  24
+
+    Figure 12.  Example of CRC Calculation written in C...................  25
+
+    Figure 13.  Data Flow: Receiver has CRC Option, Sender Doesn't........  27
+
+    Figure 14.  Receiver and Sender Both have CRC Option..................  28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                      - ii -
+
+
+
+
diff --git a/memdump/ymsend.c b/memdump/ymsend.c
new file mode 100644 (file)
index 0000000..b4b16a5
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Ymodem send routine.  Only supports 1K blocks and CRC mode.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "ymsend.h"
+
+enum {
+  SOH = 0x01,
+  STX = 0x02,
+  EOT = 0x04,
+  ACK = 0x06,
+  NAK = 0x15,
+  CAN = 0x18,
+};
+
+/*
+ * Append a CRC16 to a block
+ */
+static void add_crc16(uint8_t *blk, int len)
+{
+  static const uint16_t crctab[256] = {
+    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+  };
+  uint16_t crc = 0;
+
+  while (len--)
+    crc = crctab[(crc >> 8) ^ *blk++] ^ crc << 8;
+
+  *blk++ = crc >> 8;
+  *blk = crc;
+}
+
+static void send_ack_blk(struct serial_if *sif, const void *data, size_t bytes)
+{
+  uint8_t ack_buf;
+
+  if (bytes)
+    sif->write(sif, data, bytes);
+
+  do {
+    do {
+      sif->read(sif, &ack_buf, 1);
+    } while (ack_buf != ACK && ack_buf != NAK);
+  } while (ack_buf == NAK);
+}
+
+static const uint8_t eot_buf = EOT;
+
+void send_ymodem(struct serial_if *sif,  struct file_info *fileinfo,
+                void (*gen_data)(void *, size_t, struct file_info *, size_t))
+{
+  uint8_t ack_buf, blk_buf[1024+5], *np, *q;
+  const char *p;
+  size_t len, lx, pos;
+  int blk;
+
+  /* Wait for initial handshake */
+  printf("Waiting for handshake...\n");
+  do {
+    sif->read(sif, &ack_buf, 1);
+  } while (ack_buf != 'C');
+
+  /* Send initial batch header (filename, length etc.) */
+  q = blk_buf + 3;
+  p = fileinfo->name;
+  while (*p)
+    *q++ = *p++;
+  *q++ = '\0';
+
+  lx = len = fileinfo->size;
+  do {
+    q++;
+    lx /= 10;
+  } while (lx);
+
+  np = q;
+  lx = len;
+  do {
+    *--np = (lx % 10) + '0';
+    lx /= 10;
+  } while (lx);
+
+  while (q < blk_buf+1024+3)
+    *q++ = 0;
+
+  blk = 0;
+  pos = 0;
+  do {
+    if (blk != 0) {
+      gen_data(blk_buf+3, 1024, fileinfo, pos);
+      pos += 1024;
+      len = (len < 1024) ? 0 : len-1024;
+    }
+
+    blk_buf[0] = STX;
+    blk_buf[1] = blk;
+    blk_buf[2] = ~blk;
+    add_crc16(blk_buf+3, 1024);
+
+    printf("Sending block %d...\r", blk);
+    send_ack_blk(sif, blk_buf, 1024+5);
+
+    blk++;
+  } while(len);
+
+  printf("\nSending EOT...\n");
+  send_ack_blk(sif, &eot_buf, 1);
+  printf("Done.\n");
+}
+
+void end_ymodem(struct serial_if *sif)
+{
+  uint8_t ack_buf;
+  uint8_t blk_buf[128+5];
+
+  /* Wait for initial handshake */
+  printf("END: Waiting for handshake...\n");
+  do {
+    sif->read(sif, &ack_buf, 1);
+  } while (ack_buf != 'C');
+
+  memset(blk_buf, 0, sizeof blk_buf);
+  blk_buf[0] = SOH;
+  blk_buf[1] = 0;
+  blk_buf[2] = 0xff;
+  add_crc16(blk_buf+3, 128);
+  printf("Sending block 0...\n");
+  send_ack_blk(sif, &blk_buf, 128+5);
+
+  printf("Sending EOT...\n");
+  sif->write(sif, &eot_buf, 1);
+  /* rb doesn't ack the EOT for an end batch transfer. */
+  printf("Done.\n");
+}
diff --git a/memdump/ymsend.h b/memdump/ymsend.h
new file mode 100644 (file)
index 0000000..9bcd540
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef YMSEND_H
+#define YMSEND_H
+
+#include "mystuff.h"
+
+struct serial_if {
+  int port;
+  void *pvt;
+  void (*read)(struct serial_if *, void *, size_t);
+  void (*write)(struct serial_if *, const void *, size_t);
+};
+
+struct file_info {
+  const char *name;
+  size_t size;
+  void *pvt;
+};
+
+void send_ymodem(struct serial_if *, struct file_info *,
+                void (*)(void *, size_t, struct file_info *, size_t));
+void end_ymodem(struct serial_if *);
+
+int serial_init(struct serial_if *sif);
+void serial_read(struct serial_if *sif, void *data, size_t n);
+void serial_write(struct serial_if *sif, const void *data, size_t n);
+
+#endif /* YMSEND_H */