aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-02-08 14:39:20 -0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-08 14:39:20 -0800
commitcbbf4aa64d4f7f6d0e3d94b8114a19c0a2ec77ff (patch)
treef95d95d54790321e1db19208bea61dd4d2564224
parentaddaeaeb3949d576c4e0eb5cfc133b7c3bcfa8fa (diff)
parent60701611cfd3242f5ed4dc8fa985477eb53ad202 (diff)
downloadsyslinux.git-cbbf4aa64d4f7f6d0e3d94b8114a19c0a2ec77ff.tar.gz
syslinux.git-cbbf4aa64d4f7f6d0e3d94b8114a19c0a2ec77ff.tar.xz
syslinux.git-cbbf4aa64d4f7f6d0e3d94b8114a19c0a2ec77ff.zip
Merge branch 'master' into i915res
-rw-r--r--Makefile3
-rw-r--r--com32/Makefile3
-rw-r--r--com32/include/syslinux/config.h2
-rw-r--r--com32/include/syslinux/pxe.h7
-rw-r--r--com32/lib/Makefile1
-rw-r--r--com32/lib/sys/vesa/background.c46
-rw-r--r--com32/lib/syslinux/pxe_dns.c70
-rw-r--r--com32/sysdump/Makefile60
-rw-r--r--com32/sysdump/README19
-rw-r--r--com32/sysdump/backend.h54
-rw-r--r--com32/sysdump/be_tftp.c143
-rw-r--r--com32/sysdump/be_ymodem.c175
-rw-r--r--com32/sysdump/cpio.c75
-rw-r--r--com32/sysdump/cpuid.c112
-rw-r--r--com32/sysdump/ctime.c70
-rw-r--r--com32/sysdump/ctime.h8
-rw-r--r--com32/sysdump/data.h2
-rw-r--r--com32/sysdump/dmi.c126
-rw-r--r--com32/sysdump/main.c97
-rw-r--r--com32/sysdump/memmap.c81
-rw-r--r--com32/sysdump/memory.c51
-rw-r--r--com32/sysdump/pci.c70
-rw-r--r--com32/sysdump/serial.c169
-rw-r--r--com32/sysdump/serial.h19
-rw-r--r--com32/sysdump/srecsend.h9
-rw-r--r--com32/sysdump/sysdump.h14
-rw-r--r--com32/sysdump/vesa.c60
-rw-r--r--com32/sysdump/ymodem.txt2108
-rw-r--r--com32/sysdump/zout.c99
-rw-r--r--core/comboot.inc2
-rw-r--r--core/pxelinux.asm1
-rw-r--r--doc/comboot.txt1
-rw-r--r--doc/memdisk.txt15
-rwxr-xr-xgen-id.sh5
-rw-r--r--gpxe/gpxe.diff58
-rw-r--r--gpxe/src/config/general.h2
-rw-r--r--gpxe/src/core/malloc.c4
-rw-r--r--gpxe/src/hci/shell_banner.c3
-rw-r--r--gpxe/src/include/gpxe/tcp.h4
-rw-r--r--memdisk/setup.c15
-rw-r--r--memdump/Makefile2
-rw-r--r--memdump/file.h25
-rw-r--r--memdump/main.c30
-rw-r--r--memdump/serial.c5
-rw-r--r--memdump/srecsend.c75
-rw-r--r--memdump/srecsend.h10
-rw-r--r--memdump/stdbool.h32
-rw-r--r--memdump/ymsend.h18
48 files changed, 4003 insertions, 57 deletions
diff --git a/Makefile b/Makefile
index d0f5e71d..d9f43fc3 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,8 @@ include $(topdir)/MCONFIG
# List of module objects that should be installed for all derivatives
MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \
com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
- com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32
+ com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
+ com32/sysdump/*.c32
# syslinux.exe is BTARGET so as to not require everyone to have the
# mingw suite installed
diff --git a/com32/Makefile b/com32/Makefile
index 69a125e6..3821e581 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,3 +1,4 @@
-SUBDIRS = lib gpllib libutil modules mboot menu samples rosh cmenu hdt gfxboot
+SUBDIRS = lib gpllib libutil modules mboot menu samples rosh cmenu \
+ hdt gfxboot sysdump
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 168a5160..868b0f10 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -110,7 +110,7 @@ union syslinux_derivative_info {
uint32_t _edi, _esi, _ebp, _esp, _ebx;
uint16_t apiver;
uint16_t _dxh;
- uint32_t _ecx;
+ uint32_t myip;
uint8_t filesystem, ah;
uint16_t _axh;
uint32_t _eflags;
diff --git a/com32/include/syslinux/pxe.h b/com32/include/syslinux/pxe.h
index 037642bc..6e2a769b 100644
--- a/com32/include/syslinux/pxe.h
+++ b/com32/include/syslinux/pxe.h
@@ -37,6 +37,7 @@
#include <stdint.h>
#include <netinet/in.h>
#include <klibc/compiler.h>
+#include <com32.h>
/* PXE spec structures and definitions. These mostly follow the PXE
spec, except when the PXE spec is unnecessarily stupid. Of course,
@@ -57,10 +58,7 @@ typedef struct {
uint16_t segsize;
} __packed pxe_segdesc_t;
-typedef struct {
- uint16_t offs;
- uint16_t seg;
-} segoff16_t;
+typedef far_ptr_t segoff16_t;
typedef struct {
uint8_t opcode;
@@ -522,5 +520,6 @@ typedef struct s_PXENV_UNDI_ISR {
/* SYSLINUX-defined PXE utility functions */
int pxe_get_cached_info(int level, void **buf, size_t * len);
int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE * gnt);
+uint32_t pxe_dns(const char *hostname);
#endif /* _SYSLINUX_PXE_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index bee7e8a1..0daa157f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -109,6 +109,7 @@ LIBOBJS = \
syslinux/initramfs_archive.o \
\
syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
+ syslinux/pxe_dns.o \
\
syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \
syslinux/setadv.o \
diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c
index 2e573846..8d732395 100644
--- a/com32/lib/sys/vesa/background.c
+++ b/com32/lib/sys/vesa/background.c
@@ -75,26 +75,54 @@ static void draw_background(void)
__vesacon_redraw_text();
}
+/*
+ * Tile an image in the UL corner across the entire screen
+ */
+static void tile_image(int width, int height)
+{
+ int xsize = __vesa_info.mi.h_res;
+ int ysize = __vesa_info.mi.v_res;
+ int x, y, yr;
+ int xl, yl;
+ uint32_t *sp, *dp, *drp, *dtp;
+
+ drp = __vesacon_background;
+ for (y = 0 ; y < ysize ; y += height) {
+ yl = min(height, ysize-y);
+ dtp = drp;
+ for (x = 0 ; x < xsize ; x += width) {
+ xl = min(width, xsize-x);
+ if (x || y) {
+ sp = __vesacon_background;
+ dp = dtp;
+ for (yr = 0 ; yr < yl ; yr++) {
+ memcpy(dp, sp, xl*sizeof(uint32_t));
+ dp += xsize;
+ sp += xsize;
+ }
+ }
+ dtp += xl;
+ }
+ drp += xsize*height;
+ }
+}
+
static int read_png_file(FILE * fp)
{
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
- png_infop end_ptr = NULL;
#if 0
png_color_16p image_background;
static const png_color_16 my_background = { 0, 0, 0, 0, 0 };
#endif
png_bytep row_pointers[__vesa_info.mi.v_res], rp;
- int passes;
int i;
int rv = -1;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-
info_ptr = png_create_info_struct(png_ptr);
- end_ptr = png_create_info_struct(png_ptr);
- if (!png_ptr || !info_ptr || !end_ptr || setjmp(png_jmpbuf(png_ptr)))
+ if (!png_ptr || !info_ptr || setjmp(png_jmpbuf(png_ptr)))
goto err;
png_init_io(png_ptr, fp);
@@ -146,16 +174,15 @@ static int read_png_file(FILE * fp)
rp += __vesa_info.mi.h_res << 2;
}
- passes = png_set_interlace_handling(png_ptr);
+ png_read_image(png_ptr, row_pointers);
- for (i = 0; i < passes; i++)
- png_read_rows(png_ptr, row_pointers, NULL, info_ptr->height);
+ tile_image(info_ptr->width, info_ptr->height);
rv = 0;
err:
if (png_ptr)
- png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
return rv;
}
@@ -198,6 +225,7 @@ static int read_jpeg_file(FILE * fp, uint8_t * header, int len)
tinyjpeg_set_bytes_per_row(jdec, bytes_per_row, 1);
tinyjpeg_decode(jdec, TINYJPEG_FMT_BGRA32);
+ tile_image(width, height);
rv = 0;
diff --git a/com32/lib/syslinux/pxe_dns.c b/com32/lib/syslinux/pxe_dns.c
new file mode 100644
index 00000000..9ab95137
--- /dev/null
+++ b/com32/lib/syslinux/pxe_dns.c
@@ -0,0 +1,70 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * pxe_dns.c
+ *
+ * Resolve a hostname via DNS
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <com32.h>
+
+#include <syslinux/pxe.h>
+
+/* Returns the status code from PXE (0 on success),
+ or -1 on invocation failure */
+uint32_t pxe_dns(const char *hostname)
+{
+ com32sys_t regs;
+ union {
+ unsigned char b[4];
+ uint32_t ip;
+ } q;
+
+ /* Is this a dot-quad? */
+ if (sscanf(hostname, "%hhu.%hhu.%hhu.%hhu",
+ &q.b[0], &q.b[1], &q.b[2], &q.b[3]) == 4)
+ return q.ip;
+
+ memset(&regs, 0, sizeof regs);
+ regs.eax.w[0] = 0x0010;
+ regs.es = SEG(__com32.cs_bounce);
+ regs.ebx.w[0] = OFFS(__com32.cs_bounce);
+
+ strcpy((char *)__com32.cs_bounce, hostname);
+
+ __intcall(0x22, &regs, &regs);
+
+ if (regs.eflags.l & EFLAGS_CF)
+ return 0;
+
+ return regs.eax.l;
+}
diff --git a/com32/sysdump/Makefile b/com32/sysdump/Makefile
new file mode 100644
index 00000000..bffee3a2
--- /dev/null
+++ b/com32/sysdump/Makefile
@@ -0,0 +1,60 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+## Copyright 2010 Intel Corporation; author: H. Peter Anvin
+##
+## 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., 51 Franklin St, Fifth Floor,
+## Boston MA 02110-1301, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## Simple menu system
+##
+
+topdir = ../..
+include ../MCONFIG
+-include $(topdir)/version.mk
+
+LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC)
+LNXLIBS = ../libutil/libutil_lnx.a
+
+MODULES = sysdump.c32
+TESTFILES =
+
+SRCS = $(wildcard *.c)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+
+# The DATE is set on the make command line when building binaries for
+# official release. Otherwise, substitute a hex string that is pretty much
+# guaranteed to be unique to be unique from build to build.
+ifndef HEXDATE
+HEXDATE := $(shell $(PERL) $(topdir)/now.pl $(SRCS) $(wildcard *.h))
+endif
+ifndef DATE
+DATE := $(shell sh $(topdir)/gen-id.sh $(VERSION) $(HEXDATE))
+endif
+
+CFLAGS += -DDATE='"$(DATE)"'
+
+all: $(MODULES) $(TESTFILES)
+
+sysdump.elf : $(OBJS) $(LIBS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+ rm -f *.lnx
+
+spotless: clean
+ rm -f *.lss *.c32 *.com
+ rm -f *~ \#*
+
+install:
+
+-include .*.d
diff --git a/com32/sysdump/README b/com32/sysdump/README
new file mode 100644
index 00000000..2b825775
--- /dev/null
+++ b/com32/sysdump/README
@@ -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/com32/sysdump/backend.h b/com32/sysdump/backend.h
new file mode 100644
index 00000000..0926c8d5
--- /dev/null
+++ b/com32/sysdump/backend.h
@@ -0,0 +1,54 @@
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <zlib.h>
+#include "serial.h"
+
+/* Backend flags */
+#define BE_NEEDLEN 0x01
+
+struct backend {
+ const char *name;
+ const char *helpmsg;
+ int minargs;
+
+ size_t dbytes;
+ size_t zbytes;
+ const char **argv;
+
+ uint32_t now;
+
+ int (*write)(struct backend *);
+
+ z_stream zstream;
+ char *outbuf;
+ size_t alloc;
+};
+
+/* zout.c */
+int init_data(struct backend *be, const char *argv[]);
+int write_data(struct backend *be, const void *buf, size_t len);
+int flush_data(struct backend *be);
+
+/* cpio.c */
+#define cpio_init init_data
+int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
+ const char *filename);
+int cpio_mkdir(struct backend *be, const char *filename);
+int cpio_writefile(struct backend *be, const char *filename,
+ const void *data, size_t len);
+int cpio_close(struct backend *be);
+#define MODE_FILE 0100644
+#define MODE_DIR 0040755
+
+/* backends.c */
+struct backend *get_backend(const char *name);
+
+/* backends */
+extern struct backend be_tftp;
+extern struct backend be_ymodem;
+
+#endif /* BACKEND_H */
diff --git a/com32/sysdump/be_tftp.c b/com32/sysdump/be_tftp.c
new file mode 100644
index 00000000..07fdb084
--- /dev/null
+++ b/com32/sysdump/be_tftp.c
@@ -0,0 +1,143 @@
+/*
+ * TFTP data output backend
+ */
+
+#include <string.h>
+#include <syslinux/pxe.h>
+#include <syslinux/config.h>
+#include <netinet/in.h>
+#include <sys/times.h>
+
+#include "backend.h"
+
+enum tftp_opcode {
+ TFTP_RRQ = 1,
+ TFTP_WRQ = 2,
+ TFTP_DATA = 3,
+ TFTP_ACK = 4,
+ TFTP_ERROR = 5,
+};
+
+struct tftp_state {
+ uint32_t my_ip;
+ uint32_t srv_ip;
+ uint16_t my_port;
+ uint16_t srv_port;
+ uint16_t seq;
+};
+
+static int send_ack_packet(struct tftp_state *tftp,
+ const void *pkt, size_t len)
+{
+ com32sys_t ireg, oreg;
+ t_PXENV_UDP_WRITE *uw = __com32.cs_bounce;
+ t_PXENV_UDP_READ *ur = __com32.cs_bounce;
+ clock_t start;
+ static const clock_t timeouts[] = {
+ 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31,
+ 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 0
+ };
+ const clock_t *timeout;
+
+ memset(&ireg, 0, sizeof ireg);
+ ireg.eax.w[0] = 0x0009;
+
+ for (timeout = timeouts ; *timeout ; timeout++) {
+ memset(uw, 0, sizeof uw);
+ memcpy(uw+1, pkt, len);
+ uw->ip = tftp->srv_ip;
+ uw->src_port = tftp->my_port;
+ uw->dst_port = tftp->srv_port ? tftp->srv_port : htons(69);
+ uw->buffer_size = len;
+ uw->buffer = FAR_PTR(uw+1);
+
+ ireg.ebx.w[0] = PXENV_UDP_WRITE;
+ ireg.es = SEG(uw);
+ ireg.edi.w[0] = OFFS(uw);
+
+ __intcall(0x22, &ireg, &oreg);
+
+ start = times(NULL);
+
+ do {
+ memset(ur, 0, sizeof ur);
+ ur->src_ip = tftp->srv_ip;
+ ur->dest_ip = tftp->my_ip;
+ ur->s_port = tftp->srv_port;
+ ur->d_port = tftp->my_port;
+ ur->buffer_size = __com32.cs_bounce_size - sizeof *ur;
+ ur->buffer = FAR_PTR(ur+1);
+
+ ireg.ebx.w[0] = PXENV_UDP_READ;
+ ireg.es = SEG(ur);
+ ireg.edi.w[0] = OFFS(ur);
+ __intcall(0x22, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) &&
+ ur->status == PXENV_STATUS_SUCCESS &&
+ tftp->srv_ip == ur->src_ip &&
+ (tftp->srv_port == 0 ||
+ tftp->srv_port == ur->s_port)) {
+ uint16_t *xb = (uint16_t *)(ur+1);
+ if (ntohs(xb[0]) == TFTP_ACK &&
+ ntohs(xb[1]) == tftp->seq) {
+ tftp->srv_port = ur->s_port;
+ return 0; /* All good! */
+ } else if (ntohs(xb[1]) == TFTP_ERROR) {
+ return -1; /* All bad! */
+ }
+ }
+ } while ((clock_t)(times(NULL) - start) < *timeout);
+ }
+
+ return -1; /* No success... */
+}
+
+static int be_tftp_write(struct backend *be)
+{
+ static uint16_t local_port = 0x4000;
+ struct tftp_state tftp;
+ char buffer[512+4+6];
+ int nlen;
+ const union syslinux_derivative_info *sdi =
+ syslinux_derivative_info();
+ const char *data = be->outbuf;
+ size_t len = be->zbytes;
+ size_t chunk;
+
+ tftp.my_ip = sdi->pxe.myip;
+ tftp.my_port = htons(local_port++);
+ tftp.srv_ip = pxe_dns(be->argv[1]);
+ tftp.srv_port = 0;
+ tftp.seq = 0;
+
+ buffer[0] = 0;
+ buffer[1] = TFTP_WRQ;
+ nlen = strlcpy(buffer+2, be->argv[0], 512);
+ memcpy(buffer+3+nlen, "octet", 6);
+
+ if (send_ack_packet(&tftp, buffer, 2+nlen+1+6))
+ return -1;
+
+ do {
+ chunk = len >= 512 ? 512 : len;
+
+ buffer[1] = TFTP_DATA;
+ *((uint16_t *)(buffer+2)) = htons(++tftp.seq);
+ memcpy(buffer+4, data, chunk);
+ data += chunk;
+ len -= chunk;
+
+ if (send_ack_packet(&tftp, buffer, chunk+4))
+ return -1;
+ } while (chunk == 512);
+
+ return 0;
+}
+
+struct backend be_tftp = {
+ .name = "tftp",
+ .helpmsg = "filename tftp_server",
+ .minargs = 2,
+ .write = be_tftp_write,
+};
diff --git a/com32/sysdump/be_ymodem.c b/com32/sysdump/be_ymodem.c
new file mode 100644
index 00000000..316b3d4e
--- /dev/null
+++ b/com32/sysdump/be_ymodem.c
@@ -0,0 +1,175 @@
+/*
+ * Ymodem send routine. Only supports 1K blocks and CRC mode.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include "backend.h"
+#include "serial.h"
+
+enum {
+ SOH = 0x01,
+ STX = 0x02,
+ EOT = 0x04,
+ ACK = 0x06,
+ NAK = 0x15,
+ CAN = 0x18,
+};
+
+struct ymodem_state {
+ struct serial_if serial;
+ unsigned int seq, blocks;
+};
+
+/*
+ * 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(struct ymodem_state *ym, const uint8_t *blk,
+ size_t bytes);
+
+static void send_ack_blk(struct ymodem_state *ym, uint8_t *blk)
+{
+ printf("Sending block %u/%u...\r", ym->seq, ym->blocks);
+
+ blk[0] = STX;
+ blk[1] = ym->seq++;
+ blk[2] = ~blk[1];
+ add_crc16(blk+3, 1024);
+
+ send_ack(ym, blk, 1024+5);
+}
+
+static void send_ack(struct ymodem_state *ym, const uint8_t *blk, size_t bytes)
+{
+ uint8_t ack_buf;
+
+ do {
+ serial_write(&ym->serial, blk, bytes);
+
+ do {
+ serial_read(&ym->serial, &ack_buf, 1);
+ } while (ack_buf != ACK && ack_buf != NAK);
+ } while (ack_buf == NAK);
+}
+
+static int be_ymodem_write(struct backend *be)
+{
+ static const uint8_t eot_buf = EOT;
+ uint8_t ack_buf;
+ uint8_t blk_buf[1024 + 5];
+ struct ymodem_state ym;
+ const char *buf;
+ size_t len, chunk;
+ const char ymodem_banner[] = "Now begin Ymodem download...\r\n";
+
+ buf = be->outbuf;
+ len = be->zbytes;
+
+ putchar('\n');
+
+ ym.seq = 0;
+ ym.blocks = (len+1023)/1024;
+
+ /* Initialize serial port */
+ if (serial_init(&ym.serial, &be->argv[1]))
+ return -1;
+
+ /* Write banner */
+ printf("Writing banner...\n");
+ serial_write(&ym.serial, ymodem_banner, sizeof ymodem_banner-1);
+
+ /* Wait for initial handshake */
+ printf("Waiting for handshake...\n");
+ do {
+ serial_read(&ym.serial, &ack_buf, 1);
+ } while (ack_buf != 'C');
+
+ /* Send filename block */
+ memset(blk_buf, 0, sizeof blk_buf);
+ snprintf((char *)blk_buf+3, 1024, "%s%c%zu 0%o 0644",
+ be->argv[0], 0, be->zbytes, be->now);
+ send_ack_blk(&ym, blk_buf);
+
+ while (len) {
+ chunk = len < 1024 ? len : 1024;
+
+ memcpy(blk_buf+3, buf, chunk);
+ if (chunk < 1024)
+ memset(blk_buf+3+chunk, 0x1a, 1024-chunk);
+
+ send_ack_blk(&ym, blk_buf);
+ buf += chunk;
+ len -= chunk;
+ }
+
+ printf("\nSending EOT...\n");
+ send_ack(&ym, &eot_buf, 1);
+
+ printf("Waiting for handshake...\n");
+ do {
+ serial_read(&ym.serial, &ack_buf, 1);
+ } while (ack_buf != 'C');
+ ym.seq = 0;
+
+ printf("Sending batch termination block...\n");
+ memset(blk_buf+3, 0, 1024);
+ send_ack_blk(&ym, blk_buf);
+
+ printf("Cleaning up... \n");
+ serial_cleanup(&ym.serial);
+
+ return 0;
+}
+
+struct backend be_ymodem = {
+ .name = "ymodem",
+ .helpmsg = "filename [port [speed]]",
+ .minargs = 1,
+ .write = be_ymodem_write,
+};
diff --git a/com32/sysdump/cpio.c b/com32/sysdump/cpio.c
new file mode 100644
index 00000000..81d0d4be
--- /dev/null
+++ b/com32/sysdump/cpio.c
@@ -0,0 +1,75 @@
+/*
+ * cpio.c
+ *
+ * Write a compressed CPIO file
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <zlib.h>
+#include "backend.h"
+#include "ctime.h"
+
+int cpio_pad(struct backend *be)
+{
+ static char pad[4]; /* Up to 4 zero bytes */
+ if (be->dbytes & 3)
+ return write_data(be, pad, -be->dbytes & 3);
+ else
+ return 0;
+}
+
+int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
+ const char *filename)
+{
+ static uint32_t inode = 2;
+ char hdr[6+13*8+1];
+ int nlen = strlen(filename)+1;
+ int rv = 0;
+
+ cpio_pad(be);
+
+ sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
+ 070701, /* c_magic */
+ inode++, /* c_ino */
+ mode, /* c_mode */
+ 0, /* c_uid */
+ 0, /* c_gid */
+ 1, /* c_nlink */
+ be->now, /* c_mtime */
+ datalen, /* c_filesize */
+ 0, /* c_maj */
+ 0, /* c_min */
+ 0, /* c_rmaj */
+ 0, /* c_rmin */
+ nlen, /* c_namesize */
+ 0); /* c_chksum */
+ rv |= write_data(be, hdr, 6+13*8);
+ rv |= write_data(be, filename, nlen);
+ rv |= cpio_pad(be);
+ return rv;
+}
+
+int cpio_mkdir(struct backend *be, const char *filename)
+{
+ return cpio_hdr(be, MODE_DIR, 0, filename);
+}
+
+int cpio_writefile(struct backend *be, const char *filename,
+ const void *data, size_t len)
+{
+ int rv;
+
+ rv = cpio_hdr(be, MODE_FILE, len, filename);
+ rv |= write_data(be, data, len);
+ rv |= cpio_pad(be);
+
+ return rv;
+}
+
+int cpio_close(struct backend *be)
+{
+ return cpio_hdr(be, 0, 0, "TRAILER!!!");
+}
diff --git a/com32/sysdump/cpuid.c b/com32/sysdump/cpuid.c
new file mode 100644
index 00000000..40b20618
--- /dev/null
+++ b/com32/sysdump/cpuid.c
@@ -0,0 +1,112 @@
+/*
+ * Dump CPUID information
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <com32.h>
+#include <sys/cpu.h>
+#include "sysdump.h"
+#include "backend.h"
+
+struct cpuid_data {
+ uint32_t eax, ebx, ecx, edx;
+};
+
+struct cpuid_info {
+ uint32_t eax, ecx;
+ struct cpuid_data data;
+};
+
+static bool has_eflag(uint32_t flag)
+{
+ uint32_t f0, f1;
+
+ asm("pushfl ; "
+ "pushfl ; "
+ "popl %0 ; "
+ "movl %0,%1 ; "
+ "xorl %2,%1 ; "
+ "pushl %1 ; "
+ "popfl ; "
+ "pushfl ; "
+ "popl %1 ; "
+ "popfl"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+
+ return !!((f0^f1) & flag);
+}
+
+static inline void get_cpuid(uint32_t eax, uint32_t ecx,
+ struct cpuid_data *data)
+{
+ asm("cpuid"
+ : "=a" (data->eax), "=b" (data->ebx),
+ "=c" (data->ecx), "=d" (data->edx)
+ : "a" (eax), "c" (ecx));
+}
+
+#define CPUID_CHUNK 128
+
+void dump_cpuid(struct backend *be)
+{
+ struct cpuid_info *buf = NULL;
+ int nentry, nalloc;
+ uint32_t region;
+ struct cpuid_data base_leaf;
+ uint32_t base, leaf, count;
+ struct cpuid_data invalid_leaf;
+ struct cpuid_data data;
+
+ if (!has_eflag(EFLAGS_ID))
+ return;
+
+ printf("Dumping CPUID... ");
+
+ nentry = nalloc = 0;
+
+ /* Find out what the CPU returns for invalid leaves */
+ get_cpuid(0, 0, &base_leaf);
+ get_cpuid(base_leaf.eax+1, 0, &invalid_leaf);
+
+ for (region = 0 ; region <= 0xffff ; region++) {
+ base = region << 16;
+
+ get_cpuid(base, 0, &base_leaf);
+ if (region && !memcmp(&base_leaf, &invalid_leaf, sizeof base_leaf))
+ continue;
+
+ if ((base_leaf.eax ^ base) & 0xffff0000)
+ continue;
+
+ for (leaf = base ; leaf <= base_leaf.eax ; leaf++) {
+ get_cpuid(leaf, 0, &data);
+ count = 0;
+
+ do {
+ if (nentry >= nalloc) {
+ nalloc += CPUID_CHUNK;
+ buf = realloc(buf, nalloc*sizeof *buf);
+ if (!buf)
+ return; /* FAILED */
+ }
+ buf[nentry].eax = leaf;
+ buf[nentry].ecx = count;
+ buf[nentry].data = data;
+ nentry++;
+ count++;
+
+ get_cpuid(leaf, count, &data);
+ } while (memcmp(&data, &buf[nentry-1].data, sizeof data) &&
+ (data.eax | data.ebx | data.ecx | data.edx));
+ }
+ }
+
+ if (nentry)
+ cpio_writefile(be, "cpuid", buf, nentry*sizeof *buf);
+ free(buf);
+
+ printf("done.\n");
+}
diff --git a/com32/sysdump/ctime.c b/com32/sysdump/ctime.c
new file mode 100644
index 00000000..5af85666
--- /dev/null
+++ b/com32/sysdump/ctime.c
@@ -0,0 +1,70 @@
+#include <com32.h>
+#include <string.h>
+#include "ctime.h"
+
+static uint8_t frombcd(uint8_t v)
+{
+ uint8_t a = v & 0x0f;
+ uint8_t b = v >> 4;
+
+ return a + b*10;
+}
+
+uint32_t posix_time(void)
+{
+ /* Days from March 1 for a specific month, starting in March */
+ static const unsigned int yday[12] =
+ { 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337 };
+ com32sys_t ir, d0, d1, t0;
+ unsigned int c, y, mo, d, h, m, s;
+ uint32_t t;
+
+ memset(&ir, 0, sizeof ir);
+
+ ir.eax.b[1] = 0x04;
+ __intcall(0x1A, &ir, &d0);
+
+ ir.eax.b[1] = 0x02;
+ __intcall(0x1A, &ir, &t0);
+
+ ir.eax.b[1] = 0x04;
+ __intcall(0x1A, &ir, &d1);
+
+ if (t0.ecx.b[1] < 0x12)
+ d0 = d1;
+
+ c = frombcd(d0.ecx.b[1]);
+ y = frombcd(d0.ecx.b[0]);
+ mo = frombcd(d0.edx.b[1]);
+ d = frombcd(d0.edx.b[0]);
+
+ h = frombcd(t0.ecx.b[1]);
+ m = frombcd(t0.ecx.b[0]);
+ s = frombcd(t0.edx.b[1]);
+
+ /* We of course have no idea about the timezone, so ignore it */
+
+ /*
+ * Look for impossible dates... this code was written in 2010, so
+ * assume any century less than 20 is just broken.
+ */
+ if (c < 20)
+ c = 20;
+ y += c*100;
+
+ /* Consider Jan and Feb as the last months of the previous year */
+ if (mo < 3) {
+ y--;
+ mo += 12;
+ }
+
+ t = y*365 + y/4 - y/100 + y/400 + yday[mo-3] + d - 719469;
+ t *= 24;
+ t += h;
+ t *= 60;
+ t += m;
+ t *= 60;
+ t += s;
+
+ return t;
+}
diff --git a/com32/sysdump/ctime.h b/com32/sysdump/ctime.h
new file mode 100644
index 00000000..e6461253
--- /dev/null
+++ b/com32/sysdump/ctime.h
@@ -0,0 +1,8 @@
+#ifndef CTIME_H
+#define CTIME_H
+
+#include <inttypes.h>
+
+uint32_t posix_time(void);
+
+#endif /* CTIME_H */
diff --git a/com32/sysdump/data.h b/com32/sysdump/data.h
new file mode 100644
index 00000000..deacf721
--- /dev/null
+++ b/com32/sysdump/data.h
@@ -0,0 +1,2 @@
+#ifndef DATA_H
+#define DATA_H
diff --git a/com32/sysdump/dmi.c b/com32/sysdump/dmi.c
new file mode 100644
index 00000000..be4cce46
--- /dev/null
+++ b/com32/sysdump/dmi.c
@@ -0,0 +1,126 @@
+/*
+ * Dump DMI information in a way hopefully compatible with dmidecode
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "sysdump.h"
+#include "backend.h"
+
+struct dmi_header {
+ char signature[5];
+ uint8_t csum;
+ uint16_t tbllen;
+ uint32_t tbladdr;
+ uint16_t nstruc;
+ uint8_t revision;
+ uint8_t reserved;
+};
+
+struct smbios_header {
+ char signature[4];
+ uint8_t csum;
+ uint8_t len;
+ uint8_t major;
+ uint8_t minor;
+ uint16_t maxsize;
+ uint8_t revision;
+ uint8_t fmt[5];
+
+ struct dmi_header dmi;
+};
+
+static uint8_t checksum(const void *buf, size_t len)
+{
+ const uint8_t *p = buf;
+ uint8_t csum = 0;
+
+ while (len--)
+ csum += *p++;
+
+ return csum;
+}
+
+static bool is_old_dmi(size_t dptr)
+{
+ const struct dmi_header *dmi = (void *)dptr;
+
+ return !memcmp(dmi->signature, "_DMI_", 5) &&
+ !checksum(dmi, 0x0f);
+ return false;
+}
+
+static bool is_smbios(size_t dptr)
+{
+ const struct smbios_header *smb = (void *)dptr;
+
+ return !memcmp(smb->signature, "_SM_", 4) &&
+ !checksum(smb, smb->len) &&
+ is_old_dmi(dptr+16);
+}
+
+static void dump_smbios(struct backend *be, size_t dptr)
+{
+ const struct smbios_header *smb = (void *)dptr;
+ struct smbios_header smx = *smb;
+ char filename[32];
+
+ snprintf(filename, sizeof filename, "dmi/%05x.%08x",
+ dptr, smb->dmi.tbladdr);
+ cpio_hdr(be, MODE_FILE, smb->dmi.tbllen + 32, filename);
+
+ /*
+ * Adjust the address of the smbios table to be 32, to
+ * make dmidecode happy. The checksum on the smbios table is unchanged,
+ * since it includes the checksum on the dmi table.
+ */
+ smx.dmi.tbladdr = sizeof smx;
+ smx.dmi.csum -= checksum(&smx.dmi, 0x0f);
+
+ write_data(be, &smx, sizeof smx);
+ write_data(be, (const void *)smb->dmi.tbladdr, smb->dmi.tbllen);
+}
+
+static void dump_old_dmi(struct backend *be, size_t dptr)
+{
+ const struct dmi_header *dmi = (void *)dptr;
+ struct fake {
+ struct dmi_header dmi;
+ char pad[16];
+ } fake;
+ char filename[32];
+
+ snprintf(filename, sizeof filename, "dmi/%05x.%08x",
+ dptr, dmi->tbladdr);
+ cpio_hdr(be, MODE_FILE, dmi->tbllen + 32, filename);
+
+ /*
+ * Adjust the address of the smbios table to be 32, to
+ * make dmidecode happy.
+ */
+ fake.dmi = *dmi;
+ memset(&fake.pad, 0, sizeof fake.pad);
+ fake.dmi.tbladdr = sizeof fake;
+ fake.dmi.csum -= checksum(&fake.dmi, 0x0f);
+
+ write_data(be, &fake, sizeof fake);
+ write_data(be, (const void *)dmi->tbladdr, dmi->tbllen);
+}
+
+void dump_dmi(struct backend *be)
+{
+ size_t dptr;
+
+ cpio_mkdir(be, "dmi");
+
+ /* Search for _SM_ or _DMI_ structure */
+ for (dptr = 0xf0000 ; dptr < 0x100000 ; dptr += 16) {
+ if (is_smbios(dptr)) {
+ dump_smbios(be, dptr);
+ dptr += 16; /* Skip the subsequent DMI header */
+ } else if (is_old_dmi(dptr)) {
+ dump_old_dmi(be, dptr);
+ }
+ }
+}
diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c
new file mode 100644
index 00000000..d4a0320e
--- /dev/null
+++ b/com32/sysdump/main.c
@@ -0,0 +1,97 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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 <stdbool.h>
+#include <inttypes.h>
+#include <dprintf.h>
+#include <console.h>
+#include <sys/cpu.h>
+#include "../../version.h"
+#include "backend.h"
+#include "sysdump.h"
+
+const char program[] = "sysdump";
+const char version[] = "SYSDUMP " VERSION_STR " " DATE "\n";
+
+__noreturn die(const char *msg)
+{
+ printf("%s: %s\n", program, msg);
+ exit(1);
+}
+
+static void dump_all(struct backend *be, const char *argv[])
+{
+ cpio_init(be, argv);
+
+ cpio_writefile(be, "sysdump", version, sizeof version-1);
+
+ dump_memory_map(be);
+ dump_memory(be);
+ dump_dmi(be);
+ dump_cpuid(be);
+ dump_pci(be);
+ dump_vesa_tables(be);
+
+ cpio_close(be);
+ flush_data(be);
+}
+
+static struct backend *backends[] =
+{
+ &be_tftp,
+ &be_ymodem,
+ NULL
+};
+
+__noreturn usage(void)
+{
+ struct backend **bep, *be;
+
+ printf("Usage:\n");
+ for (bep = backends ; (be = *bep) ; bep++)
+ printf(" %s %s %s\n", program, be->name, be->helpmsg);
+
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ struct backend **bep, *be;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+ fputs(version, stdout);
+
+ if (argc < 2)
+ usage();
+
+ for (bep = backends ; (be = *bep) ; bep++) {
+ if (!strcmp(be->name, argv[1]))
+ break;
+ }
+
+ if (!be || argc < be->minargs + 2)
+ usage();
+
+ /* Do this as early as possible */
+ snapshot_lowmem();
+
+ printf("Backend: %s\n", be->name);
+
+ /* Do the actual data dump */
+ dump_all(be, (const char **)argv + 2);
+
+ return 0;
+}
diff --git a/com32/sysdump/memmap.c b/com32/sysdump/memmap.c
new file mode 100644
index 00000000..a85f0925
--- /dev/null
+++ b/com32/sysdump/memmap.c
@@ -0,0 +1,81 @@
+/*
+ * Dump memory map information
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <com32.h>
+#include "sysdump.h"
+#include "backend.h"
+
+#define E820_CHUNK 128
+struct e820_info {
+ uint32_t ebx;
+ uint32_t len;
+ uint8_t data[24];
+};
+
+static void dump_e820(struct backend *be)
+{
+ com32sys_t ireg, oreg;
+ struct e820_info *curr = __com32.cs_bounce;
+ struct e820_info *buf, *p;
+ int nentry, nalloc;
+
+ buf = p = NULL;
+ nentry = nalloc = 0;
+ memset(&ireg, 0, sizeof ireg);
+ memset(&curr, 0, sizeof curr);
+
+ ireg.eax.l = 0xe820;
+ ireg.edx.l = 0x534d4150;
+ ireg.ecx.l = sizeof curr->data;
+ ireg.es = SEG(curr->data);
+ ireg.edi.w[0] = OFFS(curr->data);
+
+ do {
+ __intcall(0x15, &ireg, &oreg);
+ if ((oreg.eflags.l & EFLAGS_CF) ||
+ oreg.eax.l != 0x534d4150)
+ break;
+
+ if (nentry >= nalloc) {
+ nalloc += E820_CHUNK;
+ buf = realloc(buf, nalloc*sizeof *buf);
+ if (!buf)
+ return; /* FAILED */
+ }
+ memcpy(buf[nentry].data, curr->data, sizeof curr->data);
+ buf[nentry].ebx = ireg.ebx.l;
+ buf[nentry].len = oreg.ecx.l;
+ nentry++;
+
+ ireg.ebx.l = oreg.ebx.l;
+ } while (ireg.ebx.l);
+
+ if (nentry)
+ cpio_writefile(be, "memmap/15e820", buf, nentry*sizeof *buf);
+ free(buf);
+}
+
+void dump_memory_map(struct backend *be)
+{
+ com32sys_t ireg, oreg;
+
+ cpio_mkdir(be, "memmap");
+
+ memset(&ireg, 0, sizeof ireg);
+ __intcall(0x12, &ireg, &oreg);
+ cpio_writefile(be, "memmap/12", &oreg, sizeof oreg);
+
+ ireg.eax.b[1] = 0x88;
+ __intcall(0x15, &ireg, &oreg);
+ cpio_writefile(be, "memmap/1588", &oreg, sizeof oreg);
+
+ ireg.eax.w[0] = 0xe801;
+ __intcall(0x15, &ireg, &oreg);
+ cpio_writefile(be, "memmap/15e801", &oreg, sizeof oreg);
+
+ dump_e820(be);
+}
diff --git a/com32/sysdump/memory.c b/com32/sysdump/memory.c
new file mode 100644
index 00000000..6552e7f3
--- /dev/null
+++ b/com32/sysdump/memory.c
@@ -0,0 +1,51 @@
+/*
+ * Dump memory
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/cpu.h>
+#include "sysdump.h"
+#include "backend.h"
+
+static char *lowmem;
+static size_t lowmem_len;
+
+void *zero_addr; /* Hack to keep gcc from complaining */
+
+void snapshot_lowmem(void)
+{
+ extern void _start(void);
+
+ lowmem_len = (size_t)_start;
+ lowmem = malloc(lowmem_len);
+ if (lowmem) {
+ printf("Snapshotting lowmem... ");
+ cli();
+ memcpy(lowmem, zero_addr, lowmem_len);
+ sti();
+ printf("ok\n");
+ }
+}
+
+static void dump_memory_range(struct backend *be, const void *where,
+ const void *addr, size_t len)
+{
+ char filename[32];
+
+ sprintf(filename, "memory/%08zx", (size_t)addr);
+ cpio_writefile(be, filename, where, len);
+}
+
+void dump_memory(struct backend *be)
+{
+ printf("Dumping memory... ");
+
+ cpio_mkdir(be, "memory");
+
+ if (lowmem)
+ dump_memory_range(be, lowmem, zero_addr, lowmem_len);
+
+ printf("done.\n");
+}
diff --git a/com32/sysdump/pci.c b/com32/sysdump/pci.c
new file mode 100644
index 00000000..1d687279
--- /dev/null
+++ b/com32/sysdump/pci.c
@@ -0,0 +1,70 @@
+/*
+ * Dump PCI device headers
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/pci.h>
+#include "sysdump.h"
+#include "backend.h"
+
+static void dump_pci_device(struct backend *be, pciaddr_t a, uint8_t hdrtype)
+{
+ unsigned int bus = pci_bus(a);
+ unsigned int dev = pci_dev(a);
+ unsigned int func = pci_func(a);
+ uint8_t data[256];
+ unsigned int i;
+ char filename[32];
+
+ hdrtype &= 0x7f;
+
+ printf("Scanning PCI bus... %02x:%02x.%x\r", bus, dev, func);
+
+ /* Assume doing a full device dump is actually safe... */
+ for (i = 0; i < sizeof data; i += 4)
+ *(uint32_t *)(data+i) = pci_readl(a + i);
+
+ snprintf(filename, sizeof filename, "pci/%02x:%02x.%x",
+ bus, dev, func);
+ cpio_writefile(be, filename, data, sizeof data);
+}
+
+void dump_pci(struct backend *be)
+{
+ int cfgtype;
+ unsigned int nbus, ndev, nfunc, maxfunc;
+ pciaddr_t a;
+ uint32_t did;
+ uint8_t hdrtype;
+
+ cfgtype = pci_set_config_type(PCI_CFG_AUTO);
+ if (cfgtype == PCI_CFG_NONE)
+ return;
+
+ cpio_mkdir(be, "pci");
+
+ for (nbus = 0; nbus < MAX_PCI_BUSES; nbus++) {
+ for (ndev = 0; ndev < MAX_PCI_DEVICES; ndev++) {
+ maxfunc = 1; /* Assume a single-function device */
+
+ for (nfunc = 0; nfunc < maxfunc; nfunc++) {
+ a = pci_mkaddr(nbus, ndev, nfunc, 0);
+ did = pci_readl(a);
+
+ if (did == 0xffffffff || did == 0xffff0000 ||
+ did == 0x0000ffff || did == 0x00000000)
+ continue;
+
+ hdrtype = pci_readb(a + 0x0e);
+ if (hdrtype & 0x80)
+ maxfunc = MAX_PCI_FUNC; /* Multifunction device */
+
+ dump_pci_device(be, a, hdrtype);
+ }
+ }
+ }
+
+ printf("Scanning PCI bus... done. \n");
+}
diff --git a/com32/sysdump/serial.c b/com32/sysdump/serial.c
new file mode 100644
index 00000000..a3987531
--- /dev/null
+++ b/com32/sysdump/serial.c
@@ -0,0 +1,169 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <console.h>
+#include <sys/io.h>
+#include <sys/cpu.h>
+#include <syslinux/config.h>
+
+#include "serial.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, const char *argv[])
+{
+ const struct syslinux_serial_console_info *sci
+ = syslinux_serial_console_info();
+ uint16_t port;
+ unsigned int divisor;
+ uint8_t dll, dlm, lcr;
+
+ if (!argv[0]) {
+ if (sci->iobase) {
+ port = sci->iobase;
+ } else {
+ printf("No port number specified and not using serial console!\n");
+ return -1;
+ }
+ } else {
+ port = strtoul(argv[0], NULL, 0);
+ if (port <= 3) {
+ uint16_t addr = ((uint16_t *)0x400)[port];
+ if (!addr) {
+ printf("No serial port address found!\n");
+ return -1;
+ }
+ printf("Serial port %u is at 0x%04x\n", port, addr);
+ port = addr;
+ }
+ }
+
+ sif->port = port;
+ sif->console = false;
+
+ divisor = 1; /* Default speed = 115200 bps */
+
+ /* Check to see if this is the same as the serial console */
+ if (port == sci->iobase) {
+ /* Overlaying the console... */
+ sif->console = true;
+
+ /* Default to already configured speed */
+ divisor = sci->divisor;
+
+ /* Shut down I/O to the console for the time being */
+ openconsole(&dev_null_r, &dev_null_w);
+ }
+
+ if (argv[0] && argv[1])
+ divisor = 115200/strtoul(argv[1], NULL, 0);
+
+ cli(); /* Just in case... */
+
+ /* Save old register settings */
+ sif->old.lcr = inb(port + LCR);
+ sif->old.mcr = inb(port + MCR);
+ sif->old.iir = inb(port + IIR);
+
+ /* Set speed */
+ outb(0x83, port + LCR); /* Enable divisor access */
+ sif->old.dll = inb(port + DLL);
+ sif->old.dlm = inb(port + DLM);
+ outb(divisor, port + DLL);
+ outb(divisor >> 8, port + DLM);
+ (void)inb(port + IER); /* Synchronize */
+
+ dll = inb(port + DLL);
+ dlm = inb(port + DLM);
+ lcr = inb(port + LCR);
+ outb(0x03, port + LCR); /* Enable data access, n81 */
+ (void)inb(port + IER); /* Synchronize */
+ sif->old.ier = inb(port + IER);
+
+ /* Disable interrupts */
+ outb(0, port + IER);
+
+ sti();
+
+ if (dll != (uint8_t)divisor ||
+ dlm != (uint8_t)(divisor >> 8) ||
+ lcr != 0x83) {
+ serial_cleanup(sif);
+ printf("No serial port detected!\n");
+ return -1; /* This doesn't look like a serial port */
+ }
+
+ /* Enable 16550A FIFOs if available */
+ outb(0x01, port + FCR); /* Enable FIFO */
+ (void)inb(port + IER); /* Synchronize */
+ if (inb(port + IIR) < 0xc0)
+ outb(0x00, port + FCR); /* 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);
+ }
+}
+
+void serial_cleanup(struct serial_if *sif)
+{
+ uint16_t port = sif->port;
+
+ outb(0x83, port + LCR);
+ (void)inb(port + IER);
+ outb(sif->old.dll, port + DLL);
+ outb(sif->old.dlm, port + DLM);
+ (void)inb(port + IER);
+ outb(sif->old.lcr & 0x7f, port + LCR);
+ (void)inb(port + IER);
+ outb(sif->old.mcr, port + MCR);
+ outb(sif->old.ier, port + IER);
+ if (sif->old.iir < 0xc0)
+ outb(0x00, port + FCR); /* Disable FIFOs */
+
+ /* Re-enable console messages, if we shut them down */
+ if (sif->console)
+ openconsole(&dev_null_r, &dev_stdcon_w);
+}
diff --git a/com32/sysdump/serial.h b/com32/sysdump/serial.h
new file mode 100644
index 00000000..356f2cef
--- /dev/null
+++ b/com32/sysdump/serial.h
@@ -0,0 +1,19 @@
+#ifndef SERIAL_H
+#define SERIAL_H
+
+#include <stddef.h>
+
+struct serial_if {
+ uint16_t port;
+ bool console;
+ struct {
+ uint8_t dll, dlm, ier, iir, lcr, mcr;
+ } old;
+};
+
+int serial_init(struct serial_if *sif, const char *argv[]);
+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);
+void serial_cleanup(struct serial_if *sif);
+
+#endif /* SERIAL_H */
diff --git a/com32/sysdump/srecsend.h b/com32/sysdump/srecsend.h
new file mode 100644
index 00000000..667be20d
--- /dev/null
+++ b/com32/sysdump/srecsend.h
@@ -0,0 +1,9 @@
+#ifndef SRECSEND_H
+#define SRECSEND_H
+
+#include "file.h"
+
+void send_srec(struct serial_if *, struct file_info *,
+ void (*)(void *, size_t, struct file_info *, size_t));
+
+#endif /* SRECSEND_H */
diff --git a/com32/sysdump/sysdump.h b/com32/sysdump/sysdump.h
new file mode 100644
index 00000000..61a04a2b
--- /dev/null
+++ b/com32/sysdump/sysdump.h
@@ -0,0 +1,14 @@
+#ifndef SYSDUMP_H
+#define SYSDUMP_H
+
+struct backend;
+
+void dump_memory_map(struct backend *);
+void snapshot_lowmem(void);
+void dump_memory(struct backend *);
+void dump_dmi(struct backend *);
+void dump_cpuid(struct backend *);
+void dump_pci(struct backend *);
+void dump_vesa_tables(struct backend *);
+
+#endif /* SYSDUMP_H */
diff --git a/com32/sysdump/vesa.c b/com32/sysdump/vesa.c
new file mode 100644
index 00000000..9bdc7153
--- /dev/null
+++ b/com32/sysdump/vesa.c
@@ -0,0 +1,60 @@
+#include <string.h>
+#include <stdio.h>
+#include "../lib/sys/vesa/vesa.h"
+#include "backend.h"
+#include "sysdump.h"
+
+void dump_vesa_tables(struct backend *be)
+{
+ com32sys_t rm;
+ struct vesa_general_info *gip, gi;
+ struct vesa_mode_info *mip, mi;
+ uint16_t mode, *mode_ptr;
+ char modefile[64];
+
+ printf("Scanning VESA BIOS... ");
+
+ /* Allocate space in the bounce buffer for these structures */
+ gip = &((struct vesa_info *)__com32.cs_bounce)->gi;
+ mip = &((struct vesa_info *)__com32.cs_bounce)->mi;
+
+ memset(&rm, 0, sizeof rm);
+ memset(gip, 0, sizeof *gip);
+
+ gip->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gip);
+ rm.es = SEG(gip);
+ __intcall(0x10, &rm, &rm);
+ memcpy(&gi, gip, sizeof gi);
+
+ if (rm.eax.w[0] != 0x004F)
+ return; /* Function call failed */
+ if (gi.signature != VESA_MAGIC)
+ return; /* No magic */
+
+ cpio_mkdir(be, "vesa");
+
+ cpio_writefile(be, "vesa/global.bin", &gi, sizeof gi);
+
+ mode_ptr = GET_PTR(gi.video_mode_ptr);
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ memset(mip, 0, sizeof *mip);
+ rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
+ rm.ecx.w[0] = mode;
+ rm.edi.w[0] = OFFS(mip);
+ rm.es = SEG(mip);
+ __intcall(0x10, &rm, &rm);
+
+ /* Must be a supported mode */
+ if (rm.eax.w[0] != 0x004f)
+ continue;
+
+ memcpy(&mi, mip, sizeof mi);
+
+ sprintf(modefile, "vesa/mode%04x.bin", mode);
+ cpio_writefile(be, modefile, &mi, sizeof mi);
+ }
+
+ printf("done.\n");
+}
diff --git a/com32/sysdump/ymodem.txt b/com32/sysdump/ymodem.txt
new file mode 100644
index 00000000..2264ff78
--- /dev/null
+++ b/com32/sysdump/ymodem.txt
@@ -0,0 +1,2108 @@
+
+
+
+ - 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/com32/sysdump/zout.c b/com32/sysdump/zout.c
new file mode 100644
index 00000000..ece934cc
--- /dev/null
+++ b/com32/sysdump/zout.c
@@ -0,0 +1,99 @@
+/*
+ * Compress input and feed it to a block-oriented back end.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <zlib.h>
+#include "backend.h"
+#include "ctime.h"
+
+#define ALLOC_CHUNK 65536
+
+int init_data(struct backend *be, const char *argv[])
+{
+ be->now = posix_time();
+ be->argv = argv;
+
+ memset(&be->zstream, 0, sizeof be->zstream);
+
+ be->zstream.next_out = NULL;
+ be->outbuf = NULL;
+ be->zstream.avail_out = be->alloc = 0;
+ be->dbytes = be->zbytes = 0;
+
+ /* Initialize a gzip data stream */
+ if (deflateInit2(&be->zstream, 9, Z_DEFLATED,
+ 16+15, 9, Z_DEFAULT_STRATEGY) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int do_deflate(struct backend *be, int flush)
+{
+ int rv;
+ char *buf;
+
+ while (1) {
+ rv = deflate(&be->zstream, flush);
+ be->zbytes = be->alloc - be->zstream.avail_out;
+ if (be->zstream.avail_out)
+ return rv; /* Not an issue of output space... */
+
+ buf = realloc(be->outbuf, be->alloc + ALLOC_CHUNK);
+ if (!buf)
+ return Z_MEM_ERROR;
+ be->outbuf = buf;
+ be->alloc += ALLOC_CHUNK;
+ be->zstream.next_out = (void *)(buf + be->zbytes);
+ be->zstream.avail_out = be->alloc - be->zbytes;
+ }
+}
+
+
+int write_data(struct backend *be, const void *buf, size_t len)
+{
+ int rv = Z_OK;
+
+ be->zstream.next_in = (void *)buf;
+ be->zstream.avail_in = len;
+
+ be->dbytes += len;
+
+ while (be->zstream.avail_in) {
+ rv = do_deflate(be, Z_NO_FLUSH);
+ if (rv < 0) {
+ printf("do_deflate returned %d\n", rv);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Output the data and shut down the stream */
+int flush_data(struct backend *be)
+{
+ int rv = Z_OK;
+
+ while (rv != Z_STREAM_END) {
+ rv = do_deflate(be, Z_FINISH);
+ if (rv < 0)
+ return -1;
+ }
+
+ printf("Uploading data, %u bytes... ", be->zbytes);
+
+ if (be->write(be))
+ return -1;
+
+ free(be->outbuf);
+ be->outbuf = NULL;
+ be->dbytes = be->zbytes = be->alloc = 0;
+
+ printf("done.\n");
+ return 0;
+}
diff --git a/core/comboot.inc b/core/comboot.inc
index cdba16d5..82b158f8 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -577,6 +577,8 @@ comapi_derinfo:
mov P_SI,ax
mov ax,[InitStack+2]
mov P_FS,ax
+ mov eax,[MyIP]
+ mov P_ECX,eax
%else
; Physical medium...
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 01159f16..6ad15845 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -901,6 +901,7 @@ local_boot:
mov si,localboot_msg
call writestr_early
; Restore the environment we were called with
+ call reset_pxe
call cleanup_hardware
lss sp,[InitStack]
pop gs
diff --git a/doc/comboot.txt b/doc/comboot.txt
index b3d8e648..4ef10f45 100644
--- a/doc/comboot.txt
+++ b/doc/comboot.txt
@@ -401,6 +401,7 @@ AX=000Ah [2.00] Get Derivative-Specific Information
Input: AX 000Ah
Output: AL 32h (PXELINUX)
DX PXE API version detected (DH=major, DL=minor)
+ ECX Local IP number (network byte order) [3.85]
ES:BX pointer to PXENV+ or !PXE structure
FS:SI pointer to original stack with invocation record
diff --git a/doc/memdisk.txt b/doc/memdisk.txt
index 254cb7c9..c7244abc 100644
--- a/doc/memdisk.txt
+++ b/doc/memdisk.txt
@@ -132,15 +132,22 @@ g) The following option can be used to set the real-mode stack size.
stack=size Set the stack to "size" bytes
+h) Some systems without a floppy drive have been known to have
+ problems with floppy images. To avoid that those problems, first
+ of all make sure you don't have a floppy drive configured on the
+ BIOS screen. If there is no option to configure that, or that
+ doesn't work, you can use the option:
+
+ nopass Hide all real drives of the same type (floppy or hard disk)
+
Some interesting things to note:
If you're using MEMDISK to boot DOS from a CD-ROM (using ISOLINUX),
you might find the generic El Torito CD-ROM driver by Gary Tong and
-Bart Lagerweij useful:
-
- http://www.nu2.nu/eltorito/
-
+Bart Lagerweij useful. It is now included with the Syslinux
+distribution, in the dosutil directory. See the file
+dosutil/eltorito.txt for more information.
Similarly, if you're booting DOS over the network using PXELINUX, you
can use the "keeppxe" option and use the generic PXE (UNDI) NDIS
diff --git a/gen-id.sh b/gen-id.sh
index 1b3e108b..301ea4eb 100755
--- a/gen-id.sh
+++ b/gen-id.sh
@@ -8,9 +8,10 @@
#
ver="$1"
-tim="$1"
+tim="$2"
+top=`dirname "$0"`
-if test -n "$GIT_DIR" -o -d ../.git -o -f ../.git; then
+if test -n "$GIT_DIR" -o -d "$top"/.git -o -f "$top"/.git; then
id="$(git describe)"
if test -n "$id"; then
if test x"$(echo "$id" | cut -d- -f1)" = xsyslinux; then
diff --git a/gpxe/gpxe.diff b/gpxe/gpxe.diff
index 3df08a21..57e5f416 100644
--- a/gpxe/gpxe.diff
+++ b/gpxe/gpxe.diff
@@ -13,3 +13,61 @@ index 0a9e625..de51f9f 100644
#undef DOWNLOAD_PROTO_TFTM /* Multicast Trivial File Transfer Protocol */
#undef DOWNLOAD_PROTO_SLAM /* Scalable Local Area Multicast */
+diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h
+index de51f9f..2f5a938 100644
+--- a/gpxe/src/config/general.h
++++ b/gpxe/src/config/general.h
+@@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
+ * Timer configuration
+ *
+ */
+-#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
++#define BANNER_TIMEOUT 0 /* Tenths of a second for which the shell
+ banner should appear */
+
+ /*
+diff --git a/gpxe/src/hci/shell_banner.c b/gpxe/src/hci/shell_banner.c
+index 8afefe3..b92e08e 100644
+--- a/gpxe/src/hci/shell_banner.c
++++ b/gpxe/src/hci/shell_banner.c
+@@ -41,6 +41,9 @@ int shell_banner ( void ) {
+ int wait_count;
+ int key;
+
++ if ( BANNER_TIMEOUT <= 0 )
++ return enter_shell;
++
+ printf ( "\nPress Ctrl-B for the gPXE command line..." );
+
+ /* Wait for key */
+diff --git a/gpxe/src/include/gpxe/tcp.h b/gpxe/src/include/gpxe/tcp.h
+index 7ae7eab..9dc39fc 100644
+--- a/gpxe/src/include/gpxe/tcp.h
++++ b/gpxe/src/include/gpxe/tcp.h
+@@ -286,8 +286,8 @@ struct tcp_options {
+ * actually use 65536, we use a window size of (65536-4) to ensure
+ * that payloads remain dword-aligned.
+ */
+-//#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
+-#define TCP_MAX_WINDOW_SIZE 4096
++#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
++//#define TCP_MAX_WINDOW_SIZE 4096
+
+ /**
+ * Path MTU
+diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c
+index 8b0bc24..0153748 100644
+--- a/gpxe/src/core/malloc.c
++++ b/gpxe/src/core/malloc.c
+@@ -78,9 +78,9 @@ size_t freemem;
+ /**
+ * Heap size
+ *
+- * Currently fixed at 128kB.
++ * Currently fixed at 512kB.
+ */
+-#define HEAP_SIZE ( 128 * 1024 )
++#define HEAP_SIZE ( 512 * 1024 )
+
+ /** The heap itself */
+ static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
diff --git a/gpxe/src/config/general.h b/gpxe/src/config/general.h
index de51f9f8..2f5a9387 100644
--- a/gpxe/src/config/general.h
+++ b/gpxe/src/config/general.h
@@ -31,7 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
* Timer configuration
*
*/
-#define BANNER_TIMEOUT 20 /* Tenths of a second for which the shell
+#define BANNER_TIMEOUT 0 /* Tenths of a second for which the shell
banner should appear */
/*
diff --git a/gpxe/src/core/malloc.c b/gpxe/src/core/malloc.c
index 8b0bc24d..01537483 100644
--- a/gpxe/src/core/malloc.c
+++ b/gpxe/src/core/malloc.c
@@ -78,9 +78,9 @@ size_t freemem;
/**
* Heap size
*
- * Currently fixed at 128kB.
+ * Currently fixed at 512kB.
*/
-#define HEAP_SIZE ( 128 * 1024 )
+#define HEAP_SIZE ( 512 * 1024 )
/** The heap itself */
static char heap[HEAP_SIZE] __attribute__ (( aligned ( __alignof__(void *) )));
diff --git a/gpxe/src/hci/shell_banner.c b/gpxe/src/hci/shell_banner.c
index 8afefe3d..b92e08e3 100644
--- a/gpxe/src/hci/shell_banner.c
+++ b/gpxe/src/hci/shell_banner.c
@@ -41,6 +41,9 @@ int shell_banner ( void ) {
int wait_count;
int key;
+ if ( BANNER_TIMEOUT <= 0 )
+ return enter_shell;
+
printf ( "\nPress Ctrl-B for the gPXE command line..." );
/* Wait for key */
diff --git a/gpxe/src/include/gpxe/tcp.h b/gpxe/src/include/gpxe/tcp.h
index 7ae7eab9..9dc39fcc 100644
--- a/gpxe/src/include/gpxe/tcp.h
+++ b/gpxe/src/include/gpxe/tcp.h
@@ -286,8 +286,8 @@ struct tcp_options {
* actually use 65536, we use a window size of (65536-4) to ensure
* that payloads remain dword-aligned.
*/
-//#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
-#define TCP_MAX_WINDOW_SIZE 4096
+#define TCP_MAX_WINDOW_SIZE ( 65536 - 4 )
+//#define TCP_MAX_WINDOW_SIZE 4096
/**
* Path MTU
diff --git a/memdisk/setup.c b/memdisk/setup.c
index b8eadfb7..bcb5d040 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -1119,12 +1119,18 @@ void setup(const struct real_mode_args *rm_args_ptr)
ranges[--nranges].type = -1;
}
- if (getcmditem("nopass") != CMD_NOTFOUND) {
- /* nopass specified - we're the only drive by definition */
- printf("nopass specified - we're the only drive\n");
+ if (getcmditem("nopassany") != CMD_NOTFOUND) {
+ printf("nopassany specified - we're the only drive of any kind\n");
bios_drives = 0;
pptr->drivecnt = 0;
+ no_bpt = 1;
pptr->oldint13 = driverptr + hptr->iret_offs;
+ wrz_8(BIOS_EQUIP, rdz_8(BIOS_EQUIP) & ~0xc1);
+ wrz_8(BIOS_HD_COUNT, 0);
+ } else if (getcmditem("nopass") != CMD_NOTFOUND) {
+ printf("nopass specified - we're the only drive\n");
+ bios_drives = 0;
+ pptr->drivecnt = 0;
no_bpt = 1;
} else {
/* Query drive parameters of this type */
@@ -1227,7 +1233,8 @@ void setup(const struct real_mode_args *rm_args_ptr)
if (nhd > 128)
nhd = 128;
- if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd);
+ if (!do_eltorito)
+ wrz_8(BIOS_HD_COUNT, nhd);
} else {
/* Update BIOS floppy disk count */
uint8_t equip = rdz_8(BIOS_EQUIP);
diff --git a/memdump/Makefile b/memdump/Makefile
index 05f26383..e56c7bd4 100644
--- a/memdump/Makefile
+++ b/memdump/Makefile
@@ -21,7 +21,7 @@ OPTFLAGS =
INCLUDES = -include code16.h -I.
LDFLAGS = -T com16.ld
-SRCS = main.c serial.c ymsend.c
+SRCS = main.c serial.c ymsend.c srecsend.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
diff --git a/memdump/file.h b/memdump/file.h
new file mode 100644
index 00000000..8da6973d
--- /dev/null
+++ b/memdump/file.h
@@ -0,0 +1,25 @@
+#ifndef FILE_H
+#define FILE_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 base;
+ size_t size;
+ void *pvt;
+};
+
+
+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 /* FILE_H */
diff --git a/memdump/main.c b/memdump/main.c
index 02f2a4fc..068f657e 100644
--- a/memdump/main.c
+++ b/memdump/main.c
@@ -13,8 +13,10 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <stdbool.h>
#include "mystuff.h"
#include "ymsend.h"
+#include "srecsend.h"
#include "io.h"
const char *program = "memdump";
@@ -89,10 +91,17 @@ int main(int argc, char *argv[])
.write = serial_write,
};
struct file_info finfo;
- const char serial_banner[] = "Now begin Ymodem download...\r\n";
+ const char ymodem_banner[] = "Now begin Ymodem download...\r\n";
+ bool srec = false;
+
+ if (argv[1][0] == '-') {
+ srec = argv[1][1] == 's';
+ argc--;
+ argv++;
+ }
if (argc < 4)
- die("usage: memdump port prefix start,len...");
+ die("usage: memdump [-s] port prefix start,len...");
finfo.pvt = (void *)0x400;
get_bytes(bios_ports, 8, &finfo, 0); /* Get BIOS serial ports */
@@ -110,8 +119,10 @@ int main(int argc, char *argv[])
prefix = argv[2];
- puts("Printing prefix...\n");
- sif.write(&sif, serial_banner, sizeof serial_banner - 1);
+ if (!srec) {
+ puts("Printing prefix...\n");
+ sif.write(&sif, ymodem_banner, sizeof ymodem_banner - 1);
+ }
for (i = 3; i < argc; i++) {
uint32_t start, len;
@@ -131,11 +142,16 @@ int main(int argc, char *argv[])
puts(filename);
puts("...\n");
- send_ymodem(&sif, &finfo, get_bytes);
+ if (srec)
+ send_srec(&sif, &finfo, get_bytes);
+ else
+ send_ymodem(&sif, &finfo, get_bytes);
}
- puts("Sending closing signature...\n");
- end_ymodem(&sif);
+ if (!srec) {
+ puts("Sending closing signature...\n");
+ end_ymodem(&sif);
+ }
return 0;
}
diff --git a/memdump/serial.c b/memdump/serial.c
index c8330f71..1c613d17 100644
--- a/memdump/serial.c
+++ b/memdump/serial.c
@@ -1,5 +1,8 @@
+#include <stdbool.h>
+#include <stdio.h>
+
#include "mystuff.h"
-#include "ymsend.h"
+#include "file.h"
#include "io.h"
enum {
diff --git a/memdump/srecsend.c b/memdump/srecsend.c
new file mode 100644
index 00000000..78f32edf
--- /dev/null
+++ b/memdump/srecsend.c
@@ -0,0 +1,75 @@
+/*
+ * SREC send routine.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "srecsend.h"
+
+static void make_srec(struct serial_if *sif, char type, size_t addr,
+ const void *data, size_t len)
+{
+ char buf[80]; /* More than the largest possible size */
+ char *p;
+ const uint8_t *dp = data;
+ size_t alen = (type == '0') ? 4 : 8;
+ uint8_t csum;
+
+ p = buf;
+ p += sprintf(p, "S%c%02X%0*zX", type, len+alen+1, alen, addr);
+
+ csum = (len+alen+1) + addr + (addr >> 8) + (addr >> 16) + (addr >> 24);
+ while (len) {
+ p += sprintf(p, "%02X", *dp);
+ csum += *dp;
+ dp++;
+ }
+ csum = 0xff - csum;
+ p += sprintf(p, "%02X\r\n", csum);
+
+ sif->write(sif, buf, p-buf);
+}
+
+void send_srec(struct serial_if *sif, struct file_info *fileinfo,
+ void (*gen_data) (void *, size_t, struct file_info *, size_t))
+{
+ uint8_t blk_buf[1024];
+ const uint8_t *np;
+ size_t addr, len, bytes, chunk, offset, pos;
+ int blk;
+
+ len = fileinfo->size;
+
+ make_srec(sif, '0', 0, NULL, 0);
+
+ blk = 0;
+ pos = 0;
+ addr = fileinfo->base;
+ while (len) {
+ gen_data(blk_buf, sizeof blk_buf, fileinfo, pos);
+ pos += sizeof blk_buf;
+ bytes = sizeof blk_buf;
+ if (bytes > len)
+ bytes = len;
+ len -= bytes;
+
+ printf("Sending block %d...\r", blk);
+
+ np = blk_buf;
+ while (bytes) {
+ chunk = bytes > 32 ? 32 : bytes;
+
+ make_srec(sif, '3', addr, np, chunk);
+
+ bytes -= chunk;
+ offset += chunk;
+ np += chunk;
+ addr += chunk;
+ }
+ blk++;
+ }
+
+ printf("\nSending EOT...\n");
+ make_srec(sif, '7', fileinfo->base, NULL, 0);
+ printf("Done.\n");
+}
diff --git a/memdump/srecsend.h b/memdump/srecsend.h
new file mode 100644
index 00000000..f2b08224
--- /dev/null
+++ b/memdump/srecsend.h
@@ -0,0 +1,10 @@
+#ifndef SRECSEND_H
+#define SRECSEND_H
+
+#include "mystuff.h"
+#include "file.h"
+
+void send_srec(struct serial_if *, struct file_info *,
+ void (*)(void *, size_t, struct file_info *, size_t));
+
+#endif /* SRECSEND_H */
diff --git a/memdump/stdbool.h b/memdump/stdbool.h
new file mode 100644
index 00000000..81cb05f5
--- /dev/null
+++ b/memdump/stdbool.h
@@ -0,0 +1,32 @@
+/*
+ *
+ * stdbool.h
+ */
+
+#ifndef _STDBOOL_H
+#define _STDBOOL_H
+
+#ifndef __cplusplus
+
+#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
+# if !defined(__GNUC__) ||(__GNUC__ < 3)
+typedef char _Bool; /* For C compilers without _Bool */
+# endif
+#endif
+
+#define bool _Bool
+#define true 1
+#define false 0
+
+#else
+
+/* C++ */
+#define bool bool
+#define true true
+#define false false
+
+#endif
+
+#define __bool_true_false_are_defined 1
+
+#endif /* _STDBOOL_H */
diff --git a/memdump/ymsend.h b/memdump/ymsend.h
index daed627d..b0d74384 100644
--- a/memdump/ymsend.h
+++ b/memdump/ymsend.h
@@ -2,26 +2,10 @@
#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;
-};
+#include "file.h"
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 */