aboutsummaryrefslogtreecommitdiffstats
path: root/com32
diff options
context:
space:
mode:
Diffstat (limited to 'com32')
-rw-r--r--com32/MCONFIG19
-rw-r--r--com32/Makefile3
-rw-r--r--com32/cmenu/adv_menu.tpl4
-rw-r--r--com32/cmenu/complex.c4
-rw-r--r--com32/cmenu/libmenu/menu.c10
-rw-r--r--com32/cmenu/libmenu/menu.h8
-rw-r--r--com32/cmenu/libmenu/passwords.c2
-rw-r--r--com32/gfxboot/.gitignore1
-rw-r--r--com32/gfxboot/Makefile4
-rw-r--r--com32/gfxboot/gfxboot.c240
-rw-r--r--com32/gfxboot/realmode_callback.asm2
-rw-r--r--com32/gplinclude/disk/bootloaders.h2
-rw-r--r--com32/gpllib/cpuid.c6
-rw-r--r--com32/gpllib/disk/ata.c2
-rw-r--r--com32/gpllib/disk/bootloaders.c2
-rw-r--r--com32/gpllib/dmi/dmi_processor.c52
-rw-r--r--com32/hdt/hdt-cli-syslinux.c4
-rw-r--r--com32/hdt/hdt-cli.c6
-rw-r--r--com32/hdt/hdt-cli.h2
-rw-r--r--com32/hdt/hdt-common.c2
-rw-r--r--com32/hdt/hdt-common.h2
-rw-r--r--com32/hdt/hdt-menu-syslinux.c8
-rw-r--r--com32/hdt/hdt-menu.c2
-rw-r--r--com32/hdt/hdt-menu.h2
-rw-r--r--com32/include/com32.h7
-rw-r--r--com32/include/syslinux/config.h2
-rw-r--r--com32/include/syslinux/pxe.h7
-rw-r--r--com32/include/syslinux/video.h4
-rw-r--r--com32/lib/MCONFIG2
-rw-r--r--com32/lib/Makefile13
-rw-r--r--com32/lib/chdir.c4
-rw-r--r--com32/lib/closedir.c1
-rw-r--r--com32/lib/fdopendir.c2
-rw-r--r--com32/lib/libgcc/__moddi3.c2
-rw-r--r--com32/lib/opendir.c1
-rw-r--r--com32/lib/pci/bios.c (renamed from com32/lib/pci/readbios.c)4
-rw-r--r--com32/lib/pci/pci.h3
-rw-r--r--com32/lib/pci/readx.c6
-rw-r--r--com32/lib/pci/writebios.c14
-rw-r--r--com32/lib/pci/writex.c5
-rw-r--r--com32/lib/readdir.c5
-rw-r--r--com32/lib/strcasecmp.c3
-rw-r--r--com32/lib/strcmp.c3
-rw-r--r--com32/lib/strncasecmp.c3
-rw-r--r--com32/lib/strncmp.c3
-rw-r--r--com32/lib/sys/argv.c7
-rw-r--r--com32/lib/sys/colortable.c2
-rw-r--r--com32/lib/sys/entry.S2
-rw-r--r--com32/lib/sys/libansi.c34
-rw-r--r--com32/lib/sys/vesa/background.c61
-rw-r--r--com32/lib/sys/vesa/i915resolution.c795
-rw-r--r--com32/lib/sys/vesa/initvesa.c28
-rw-r--r--com32/lib/sys/vesa/screencpy.c2
-rw-r--r--com32/lib/sys/vesa/video.h2
-rw-r--r--com32/lib/sys/vesaserial_write.c2
-rw-r--r--com32/lib/syslinux/getadv.c2
-rw-r--r--com32/lib/syslinux/load_linux.c3
-rw-r--r--com32/lib/syslinux/pxe_dns.c70
-rw-r--r--com32/lib/syslinux/video/fontquery.c54
-rw-r--r--com32/lib/syslinux/video/forcetext.c42
-rw-r--r--com32/lib/syslinux/video/reportmode.c45
-rw-r--r--com32/lib/zlib/crc32.c2
-rw-r--r--com32/mboot/Makefile2
-rw-r--r--com32/mboot/map.c4
-rw-r--r--com32/mboot/mboot.c26
-rw-r--r--com32/mboot/mboot.h9
-rw-r--r--com32/mboot/solaris.c11
-rw-r--r--com32/mboot/syslinux.c45
-rw-r--r--com32/menu/menu.h1
-rw-r--r--com32/menu/menumain.c25
-rw-r--r--com32/menu/readconfig.c5
-rw-r--r--com32/modules/Makefile3
-rw-r--r--com32/modules/chain.c229
-rw-r--r--com32/modules/cpuid.c60
-rw-r--r--com32/rosh/MCONFIG4
-rw-r--r--com32/rosh/rosh.c8
-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
98 files changed, 5362 insertions, 327 deletions
diff --git a/com32/MCONFIG b/com32/MCONFIG
index f8d9d978..0e152de3 100644
--- a/com32/MCONFIG
+++ b/com32/MCONFIG
@@ -17,10 +17,15 @@
include $(topdir)/MCONFIG
-GCCOPT := $(call gcc_ok,-std=gnu99,) \
- $(call gcc_ok,-m32,) \
- $(call gcc_ok,-fno-stack-protector,) \
- -mregparm=3 -DREGPARM=3 -march=i386 -Os
+GCCOPT := $(call gcc_ok,-std=gnu99,) \
+ $(call gcc_ok,-m32,) \
+ $(call gcc_ok,-fno-stack-protector,) \
+ $(call gcc_ok,-falign-functions=0,-malign-functions=0) \
+ $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) \
+ $(call gcc_ok,-falign-loops=0,-malign-loops=0) \
+ $(call gcc_ok,-mpreferred-stack-boundary=2,) \
+ $(call gcc_ok,-mincoming-stack-boundary=2,) \
+ -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3
com32 = $(topdir)/com32
@@ -32,11 +37,11 @@ GPLLIB =
GPLINCLUDE =
endif
-CFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
-fomit-frame-pointer -D__COM32__ \
-nostdinc -iwithprefix include \
-I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
-SFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+SFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
-fomit-frame-pointer -D__COM32__ \
-nostdinc -iwithprefix include \
-I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
@@ -45,7 +50,7 @@ COM32LD = $(com32)/lib/com32.ld
LDFLAGS = -m elf_i386 -T $(COM32LD)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
-LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
+LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g -D_GNU_SOURCE
LNXSFLAGS = -g
LNXLDFLAGS = -g
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/cmenu/adv_menu.tpl b/com32/cmenu/adv_menu.tpl
index be3c558e..a1a5d96a 100644
--- a/com32/cmenu/adv_menu.tpl
+++ b/com32/cmenu/adv_menu.tpl
@@ -183,12 +183,12 @@ TIMEOUTCODE timeout(const char *cmd)
}
}
-TIMEOUTCODE ontimeout()
+TIMEOUTCODE ontimeout(void)
{
return timeout(timeoutcmd);
}
-TIMEOUTCODE ontotaltimeout()
+TIMEOUTCODE ontotaltimeout(void)
{
return timeout(totaltimeoutcmd);
}
diff --git a/com32/cmenu/complex.c b/com32/cmenu/complex.c
index 1ac51997..f5175fa9 100644
--- a/com32/cmenu/complex.c
+++ b/com32/cmenu/complex.c
@@ -54,7 +54,7 @@ char username[12]; // Name of user currently using the system
/* End globals */
-TIMEOUTCODE ontimeout()
+TIMEOUTCODE ontimeout(void)
{
beep();
return CODE_WAIT;
@@ -244,7 +244,7 @@ t_handler_return checkbox_handler(t_menusystem * ms, t_menuitem * mi)
return rv;
}
-int main()
+int main(void)
{
t_menuitem *curr;
char cmd[160];
diff --git a/com32/cmenu/libmenu/menu.c b/com32/cmenu/libmenu/menu.c
index de4a1ee2..13754768 100644
--- a/com32/cmenu/libmenu/menu.c
+++ b/com32/cmenu/libmenu/menu.c
@@ -40,7 +40,7 @@ int isvisible(pt_menu menu, int first, int curr);
// This is same as inputc except it honors the ontimeout handler
// and calls it when needed. For the callee, there is no difference
// as this will not return unless a key has been pressed.
-static int getch()
+static int getch(void)
{
t_timeout_handler th;
int key;
@@ -615,7 +615,7 @@ uchar find_menu_num(const char *name)
// Run through all items and if they are submenus
// with a non-trivial "action" and trivial submenunum
// replace submenunum with the menu with name "action"
-void fix_submenus()
+void fix_submenus(void)
{
int i, j;
pt_menu m;
@@ -874,7 +874,7 @@ void reg_ontimeout(t_timeout_handler handler, unsigned int numsteps,
ms->tm_stepsize = stepsize;
}
-void unreg_ontimeout()
+void unreg_ontimeout(void)
{
ms->ontimeout = NULL;
}
@@ -889,7 +889,7 @@ void reg_ontotaltimeout(t_timeout_handler handler,
}
}
-void unreg_ontotaltimeout()
+void unreg_ontotaltimeout(void)
{
ms->ontotaltimeout = NULL;
}
@@ -1084,7 +1084,7 @@ void set_menu_pos(uchar row, uchar col) // Set the position of this menu.
m->col = col;
}
-pt_menuitem add_sep() // Add a separator to current menu
+pt_menuitem add_sep(void) // Add a separator to current menu
{
pt_menuitem mi;
pt_menu m;
diff --git a/com32/cmenu/libmenu/menu.h b/com32/cmenu/libmenu/menu.h
index a1356020..141d2ef0 100644
--- a/com32/cmenu/libmenu/menu.h
+++ b/com32/cmenu/libmenu/menu.h
@@ -225,7 +225,7 @@ pt_menuitem showmenus(uchar startmenu);
pt_menusystem init_menusystem(const char *title);
-void close_menusystem(); // Deallocate memory used
+void close_menusystem(void); // Deallocate memory used
void set_normal_attr(uchar normal, uchar selected, uchar inactivenormal,
uchar inactiveselected);
@@ -253,10 +253,10 @@ void reg_ontimeout(t_timeout_handler, unsigned int numsteps,
unsigned int stepsize);
// Set timeout handler, set 0 for default values.
// So stepsize=0 means numsteps is measured in centiseconds.
-void unreg_ontimeout();
+void unreg_ontimeout(void);
void reg_ontotaltimeout(t_timeout_handler, unsigned long numcentiseconds);
-void unreg_ontotaltimeout();
+void unreg_ontotaltimeout(void);
// Find the number of the menu given the name
// Returns -1 if not found
@@ -284,7 +284,7 @@ static inline void set_shortcut(uchar shortcut)
}
// Add a separator to the "current" menu
-pt_menuitem add_sep();
+pt_menuitem add_sep(void);
// Generate string based on state of checkboxes and radioitem in given menu
// and append string to existing contents of "line"
diff --git a/com32/cmenu/libmenu/passwords.c b/com32/cmenu/libmenu/passwords.c
index 06f4cfb3..44ce461f 100644
--- a/com32/cmenu/libmenu/passwords.c
+++ b/com32/cmenu/libmenu/passwords.c
@@ -148,7 +148,7 @@ void init_passwords(const char *filename)
fclose(f);
}
-void close_passwords()
+void close_passwords(void)
{
int i;
diff --git a/com32/gfxboot/.gitignore b/com32/gfxboot/.gitignore
new file mode 100644
index 00000000..1944fd61
--- /dev/null
+++ b/com32/gfxboot/.gitignore
@@ -0,0 +1 @@
+*.tmp
diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile
index 2affcdea..73133e1b 100644
--- a/com32/gfxboot/Makefile
+++ b/com32/gfxboot/Makefile
@@ -22,8 +22,8 @@ gfxboot.elf : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
realmode_callback.o: realmode_callback.asm
- nasm -f bin -O99 -o $*.tmp -l $*.lst $<
- objcopy -B i386 -I binary -O elf32-i386 \
+ $(NASM) -f bin -O99 -o $*.tmp -l $*.lst $<
+ $(OBJCOPY) -B i386 -I binary -O elf32-i386 \
--redefine-sym _binary_$*_tmp_start=$*_start \
--redefine-sym _binary_$*_tmp_end=$*_end \
--strip-symbol _binary_$*_tmp_size \
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index e1b865a1..a6c95fe1 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -116,13 +116,15 @@ typedef struct __attribute__ ((packed)) {
// menu description
typedef struct menu_s {
struct menu_s *next;
- char *label;
- char *kernel;
- char *linux;
- char *localboot;
- char *initrd;
- char *append;
- char *ipappend;
+ char *label; // config entry name
+ char *menu_label; // text to show in boot menu
+ char *kernel; // name of program to load
+ char *alt_kernel; // alternative name in case user has replaced it
+ char *linux; // de facto an alias for 'kernel'
+ char *localboot; // boot from local disk
+ char *initrd; // initrd as separate line (instead of as part of 'append')
+ char *append; // kernel args
+ char *ipappend; // append special pxelinux args (see doc)
} menu_t;
@@ -149,6 +151,9 @@ char cmdline[MAX_CMDLINE_LEN];
void *save_buf;
unsigned save_buf_size;
+// progress bar is visible
+unsigned progress_active;
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void show_message(char *file);
@@ -163,9 +168,13 @@ int gfx_init(char *file);
int gfx_menu_init(void);
void gfx_done(void);
int gfx_input(void);
+void gfx_infobox(int type, char *str1, char *str2);
+void gfx_progress_init(ssize_t kernel_size, char *label);
+void gfx_progress_update(ssize_t size);
+void gfx_progress_done(void);
ssize_t save_read(int fd, void *buf, size_t size);
void *load_one(char *file, ssize_t *file_size);
-void boot(void);
+void boot(int index);
void boot_entry(menu_t *menu_ptr, char *arg);
@@ -234,7 +243,7 @@ int main(int argc, char **argv)
}
// does not return if it succeeds
- boot();
+ boot(menu_index);
}
if(argc > 2) show_message(argv[2]);
@@ -321,59 +330,73 @@ int read_config_file(void)
if(*t) *t++ = 0;
t = skip_spaces(t);
- if(!strcmp(s, "timeout")) {
+ if(!strcasecmp(s, "timeout")) {
timeout = atoi(t);
continue;
}
- if(!strcmp(s, "default")) {
+ if(!strcasecmp(s, "default")) {
menu_default->label = strdup(t);
u = strlen(t);
if(u > label_size) label_size = u;
continue;
}
- if(!strcmp(s, "label")) {
+ if(!strcasecmp(s, "label")) {
menu_ptr = *menu_next = calloc(1, sizeof **menu_next);
menu_next = &menu_ptr->next;
menu_idx++;
- menu_ptr->label = strdup(t);
+ menu_ptr->label = menu_ptr->menu_label = strdup(t);
u = strlen(t);
if(u > label_size) label_size = u;
continue;
}
- if(!strcmp(s, "kernel") && menu_ptr) {
+ if(!strcasecmp(s, "kernel") && menu_ptr) {
menu_ptr->kernel = strdup(t);
continue;
}
- if(!strcmp(s, "linux") && menu_ptr) {
+ if(!strcasecmp(s, "linux") && menu_ptr) {
menu_ptr->linux = strdup(t);
continue;
}
- if(!strcmp(s, "localboot") && menu_ptr) {
+ if(!strcasecmp(s, "localboot") && menu_ptr) {
menu_ptr->localboot = strdup(t);
continue;
}
- if(!strcmp(s, "initrd") && menu_ptr) {
+ if(!strcasecmp(s, "initrd") && menu_ptr) {
menu_ptr->initrd = strdup(t);
continue;
}
- if(!strcmp(s, "append")) {
+ if(!strcasecmp(s, "append")) {
(menu_ptr ?: menu_default)->append = strdup(t);
u = strlen(t);
if(u > append_size) append_size = u;
continue;
}
- if(!strcmp(s, "ipappend")) {
+ if(!strcasecmp(s, "ipappend")) {
(menu_ptr ?: menu_default)->ipappend = strdup(t);
continue;
}
+
+ if(!strcasecmp(s, "menu") && menu_ptr) {
+ s = skip_spaces(t);
+ t = skip_nonspaces(s);
+ if(*t) *t++ = 0;
+ t = skip_spaces(t);
+
+ if(!strcasecmp(s, "label")) {
+ menu_ptr->menu_label = strdup(t);
+ u = strlen(t);
+ if(u > label_size) label_size = u;
+ continue;
+ }
+ }
}
fclose(f);
@@ -382,15 +405,22 @@ int read_config_file(void)
label_size++;
append_size++;
- gfx_menu.entries = menu_idx;
- gfx_menu.label_size = label_size;
- gfx_menu.arg_size = append_size;
+ // ensure we have a default entry
+ if(!menu_default->label) menu_default->label = menu->label;
- gfx_menu.default_entry = menu_default->label;
- if(!gfx_menu.default_entry && menu) {
- gfx_menu.default_entry = menu->label;
+ if(menu_default->label) {
+ for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next) {
+ if(!strcmp(menu_default->label, menu_ptr->label)) {
+ menu_default->menu_label = menu_ptr->menu_label;
+ break;
+ }
+ }
}
+ gfx_menu.entries = menu_idx;
+ gfx_menu.label_size = label_size;
+ gfx_menu.arg_size = append_size;
+ gfx_menu.default_entry = menu_default->menu_label;
gfx_menu.label_list = calloc(menu_idx, label_size);
gfx_menu.arg_list = calloc(menu_idx, append_size);
@@ -398,7 +428,7 @@ int read_config_file(void)
if(!menu_ptr->append) menu_ptr->append = menu_default->append;
if(!menu_ptr->ipappend) menu_ptr->ipappend = menu_default->ipappend;
- if(menu_ptr->label) strcpy(gfx_menu.label_list + u * label_size, menu_ptr->label);
+ if(menu_ptr->menu_label) strcpy(gfx_menu.label_list + u * label_size, menu_ptr->menu_label);
if(menu_ptr->append) strcpy(gfx_menu.arg_list + u * append_size, menu_ptr->append);
}
@@ -424,7 +454,7 @@ unsigned magic_ok(unsigned char *buf, unsigned *code_size)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Search cpio archive for gfx file.
+// Search (cpio archive) for gfx file.
//
unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size)
{
@@ -433,6 +463,8 @@ unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, u
*gfx_file_start = 0;
*code_size = 0;
+ if((code_start = magic_ok(buf, code_size))) return code_start;
+
for(i = 0; i < len;) {
if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) {
fname_len = *(unsigned short *) (buf + i + 20);
@@ -470,6 +502,8 @@ int gfx_init(char *file)
void *lowmem = lowmem_buf;
unsigned lowmem_size = lowmem_buf_size;
+ progress_active = 0;
+
printf("Loading %s...\n", file);
if(loadfile(file, &archive, &archive_size)) return 1;
@@ -571,7 +605,7 @@ int gfx_init(char *file)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-int gfx_menu_init()
+int gfx_menu_init(void)
{
com32sys_t r;
@@ -583,10 +617,12 @@ int gfx_menu_init()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-void gfx_done()
+void gfx_done(void)
{
com32sys_t r;
+ gfx_progress_done();
+
__farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_DONE], &r, &r);
}
@@ -597,7 +633,7 @@ void gfx_done()
// return:
// boot menu index (-1: go to text mode prompt)
//
-int gfx_input()
+int gfx_input(void)
{
com32sys_t r;
@@ -615,6 +651,61 @@ int gfx_input()
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void gfx_infobox(int type, char *str1, char *str2)
+{
+ com32sys_t r;
+
+ r.eax.l = type;
+ r.esi.l = (uint32_t) str1;
+ r.edi.l = (uint32_t) str2;
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INFOBOX_INIT], &r, &r);
+ r.edi.l = r.eax.l = 0;
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INPUT], &r, &r);
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_INFOBOX_DONE], &r, &r);
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void gfx_progress_init(ssize_t kernel_size, char *label)
+{
+ com32sys_t r;
+
+ if(!progress_active) {
+ r.eax.l = kernel_size >> gfx_config.sector_shift; // in sectors
+ r.esi.l = (uint32_t) label;
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_INIT], &r, &r);
+ }
+
+ progress_active = 1;
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void gfx_progress_update(ssize_t advance)
+{
+ com32sys_t r;
+
+ if(progress_active) {
+ r.eax.l = advance >> gfx_config.sector_shift; // in sectors
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r);
+ }
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+void gfx_progress_done(void)
+{
+ com32sys_t r;
+
+ if(progress_active) {
+ __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_DONE], &r, &r);
+ }
+
+ progress_active = 0;
+}
+
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Like read(2) but preserve bounce buffer.
//
ssize_t save_read(int fd, void *buf, size_t size)
@@ -636,14 +727,16 @@ void *load_one(char *file, ssize_t *file_size)
{
int fd;
void *buf = NULL;
+ char *str;
struct stat sbuf;
ssize_t size = 0, cur, i;
- com32sys_t r;
*file_size = 0;
if((fd = open(file, O_RDONLY)) == -1) {
- printf("%s: file not found\n", file);
+ asprintf(&str, "%s: file not found", file);
+ gfx_infobox(0, str, NULL);
+ free(str);
return buf;
}
@@ -655,23 +748,26 @@ void *load_one(char *file, ssize_t *file_size)
buf = malloc(size);
for(i = 1, cur = 0 ; cur < size && i > 0; cur += i) {
i = save_read(fd, buf + cur, CHUNK_SIZE);
- r.eax.l = i >> gfx_config.sector_shift;
- __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r);
+ if(i == -1) break;
+ gfx_progress_update(i);
}
}
else {
do {
buf = realloc(buf, size + CHUNK_SIZE);
i = save_read(fd, buf + size, CHUNK_SIZE);
+ if(i == -1) break;
size += i;
- r.eax.l = i >> gfx_config.sector_shift;
- __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r);
+ gfx_progress_update(i);
} while(i > 0);
}
close(fd);
if(i == -1) {
+ asprintf(&str, "%s: read error @ %d", file, size);
+ gfx_infobox(0, str, NULL);
+ free(str);
free(buf);
buf = NULL;
size = 0;
@@ -684,22 +780,54 @@ void *load_one(char *file, ssize_t *file_size)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-// Locate menu entry and boot.
+// Boot menu entry.
//
-void boot()
+// cmdline can optionally start with label string.
+//
+void boot(int index)
{
- char *label, *arg, *s;
+ char *arg, *alt_kernel;
menu_t *menu_ptr;
+ int i, label_len;
+ unsigned ipapp;
+ const struct syslinux_ipappend_strings *ipappend;
+
+ for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, index--) {
+ if(!index) break;
+ }
+
+ // invalid index or menu entry
+ if(!menu_ptr || !menu_ptr->menu_label) return;
- label = skip_spaces(cmdline);
- arg = skip_spaces(s = skip_nonspaces(label));
- *s = 0;
+ arg = skip_spaces(cmdline);
+ label_len = strlen(menu_ptr->menu_label);
- for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next) {
- if(menu_ptr->label && !strcmp(menu_ptr->label, label)) break;
+ // if it does not start with label string, assume first word is kernel name
+ if(strncmp(arg, menu_ptr->menu_label, label_len)) {
+ alt_kernel = arg;
+ arg = skip_nonspaces(arg);
+ if(*arg) *arg++ = 0;
+ if(*alt_kernel) menu_ptr->alt_kernel = alt_kernel;
+ }
+ else {
+ arg += label_len;
+ }
+
+ arg = skip_spaces(arg);
+
+ // handle IPAPPEND
+ if(menu_ptr->ipappend && (ipapp = atoi(menu_ptr->ipappend))) {
+ ipappend = syslinux_ipappend_strings();
+ for(i = 0; i < ipappend->count; i++) {
+ if((ipapp & (1 << i)) && ipappend->ptr[i]) {
+ sprintf(arg + strlen(arg), " %s", ipappend->ptr[i]);
+ }
+ }
}
boot_entry(menu_ptr, arg);
+
+ gfx_progress_done();
}
@@ -716,39 +844,41 @@ void boot_entry(menu_t *menu_ptr, char *arg)
char *file, *cmd_buf;
int fd;
struct stat sbuf;
- com32sys_t r;
char *s, *s0, *t, *initrd_arg;
if(!menu_ptr) return;
if(menu_ptr->localboot) {
gfx_done();
- syslinux_local_boot(atoi(arg));
+ syslinux_local_boot(strtol(menu_ptr->localboot, NULL, 0));
return;
}
- file = menu_ptr->kernel;
+ file = menu_ptr->alt_kernel;
+ if(!file) file = menu_ptr->kernel;
if(!file) file = menu_ptr->linux;
- if(!file) return;
+ if(!file) {
+ gfx_done();
+ asprintf(&cmd_buf, "%s %s", menu_ptr->label, arg);
+ syslinux_run_command(cmd_buf);
+ return;
+ }
// first, load kernel
- r.eax.l = 0; // kernel size in sectors
+ kernel_size = 0;
if((fd = open(file, O_RDONLY)) >= 0) {
- if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) r.eax.l = sbuf.st_size >> gfx_config.sector_shift;
+ if(!fstat(fd, &sbuf) && S_ISREG(sbuf.st_mode)) kernel_size = sbuf.st_size;
close(fd);
}
- r.esi.l = (uint32_t) file;
- __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_INIT], &r, &r);
+ gfx_progress_init(kernel_size, file);
kernel = load_one(file, &kernel_size);
if(!kernel) {
- gfx_done();
- printf("%s: read error\n", file);
return;
}
@@ -798,7 +928,7 @@ void boot_entry(menu_t *menu_ptr, char *arg)
free(s0);
- __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_DONE], &r, &r);
+ gfx_done();
syslinux_boot_linux(kernel, kernel_size, initrd, arg);
}
diff --git a/com32/gfxboot/realmode_callback.asm b/com32/gfxboot/realmode_callback.asm
index fb5461d9..2ff30f26 100644
--- a/com32/gfxboot/realmode_callback.asm
+++ b/com32/gfxboot/realmode_callback.asm
@@ -111,7 +111,7 @@ cb_fread_90:
; edx filename
;
cb_getcwd:
- mov ax,15h
+ mov ax,1fh
int 22h
mov edx,es
shl edx,4
diff --git a/com32/gplinclude/disk/bootloaders.h b/com32/gplinclude/disk/bootloaders.h
index 5a6ff9d9..56a0f4e3 100644
--- a/com32/gplinclude/disk/bootloaders.h
+++ b/com32/gplinclude/disk/bootloaders.h
@@ -14,6 +14,6 @@
#include <disk/geom.h>
#include <disk/partition.h>
-int get_bootloader_string(const struct driveinfo *, const struct part_entry *,
+int get_bootloader_string(struct driveinfo *, const struct part_entry *,
char *, const int);
#endif /* __BOOTLOADERS_H_ */
diff --git a/com32/gpllib/cpuid.c b/com32/gpllib/cpuid.c
index fa212045..f33e8958 100644
--- a/com32/gpllib/cpuid.c
+++ b/com32/gpllib/cpuid.c
@@ -232,8 +232,10 @@ void generic_identify(struct cpuinfo_x86 *c)
}
break;
case X86_VENDOR_INTEL:
- cpuid(0x4, &eax, &ebx, &ecx, &edx);
- c->x86_num_cores = ((eax & 0xfc000000) >> 26) + 1;
+ if (c->cpuid_level >= 0x00000004) {
+ cpuid(0x4, &eax, &ebx, &ecx, &edx);
+ c->x86_num_cores = ((eax & 0xfc000000) >> 26) + 1;
+ }
break;
default:
c->x86_num_cores = 1;
diff --git a/com32/gpllib/disk/ata.c b/com32/gpllib/disk/ata.c
index b0c2b63c..78f669ec 100644
--- a/com32/gpllib/disk/ata.c
+++ b/com32/gpllib/disk/ata.c
@@ -55,7 +55,7 @@ void ata_id_c_string(const uint16_t * id, unsigned char *s,
ata_id_string(id, s, ofs, len - 1);
- p = s + strnlen(s, len - 1);
+ p = s + strnlen((const char *)s, len - 1);
while (p > s && p[-1] == ' ')
p--;
*p = '\0';
diff --git a/com32/gpllib/disk/bootloaders.c b/com32/gpllib/disk/bootloaders.c
index 29aecbd4..188dd64b 100644
--- a/com32/gpllib/disk/bootloaders.c
+++ b/com32/gpllib/disk/bootloaders.c
@@ -22,7 +22,7 @@
* @buffer: pre-allocated buffer
* @buffer_size: @buffer size
**/
-int get_bootloader_string(const struct driveinfo *d, const struct part_entry *p,
+int get_bootloader_string(struct driveinfo *d, const struct part_entry *p,
char *buffer, const int buffer_size)
{
char boot_sector[SECTOR * sizeof(char)];
diff --git a/com32/gpllib/dmi/dmi_processor.c b/com32/gpllib/dmi/dmi_processor.c
index fd007da3..1cd9d1ba 100644
--- a/com32/gpllib/dmi/dmi_processor.c
+++ b/com32/gpllib/dmi/dmi_processor.c
@@ -49,7 +49,7 @@ const char *dmi_processor_type(uint8_t code)
const char *dmi_processor_family(uint8_t code, char *manufacturer)
{
/* 3.3.5.2 */
- static const char *family[] = {
+ static const char *family[256] = {
NULL, /* 0x00 */
"Other",
"Unknown",
@@ -306,54 +306,6 @@ const char *dmi_processor_family(uint8_t code, char *manufacturer)
NULL,
NULL,
NULL, /* 0xFF */
- NULL,
- NULL,
- NULL,
- NULL,
- "SH-3",
- "SH-4",
- NULL, /*0x106*/
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL, /*0x110*/
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- "ARM",
- "StrongARM",
- NULL, /*0x19A*/
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL, /*0x120*/
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL, /*0x12A*/
- NULL,
- "6x86",
- "MediaGX",
- "MII" /*0x12E*/
- /* master.mif has values beyond that, but they can't be used for DMI */
};
/* Special case for ambiguous value 0xBE */
if (code == 0xBE) {
@@ -367,7 +319,7 @@ const char *dmi_processor_family(uint8_t code, char *manufacturer)
return "Core 2 or K7";
}
- if ((code<=0x12E) && (family[code] != NULL)) {
+ if (family[code] != NULL) {
return family[code];
}
return out_of_spec;
diff --git a/com32/hdt/hdt-cli-syslinux.c b/com32/hdt/hdt-cli-syslinux.c
index 6c231ed5..302ca24a 100644
--- a/com32/hdt/hdt-cli-syslinux.c
+++ b/com32/hdt/hdt-cli-syslinux.c
@@ -42,10 +42,10 @@ void main_show_syslinux(int argc __unused, char **argv __unused,
reset_more_printf();
more_printf("SYSLINUX\n");
more_printf(" Bootloader : %s\n", hardware->syslinux_fs);
- more_printf(" Version : %s\n", hardware->sv->version_string + 2);
+ more_printf(" Version : %s\n", hardware->sv->version_string);
more_printf(" Version : %u\n", hardware->sv->version);
more_printf(" Max API : %u\n", hardware->sv->max_api);
- more_printf(" Copyright : %s\n", hardware->sv->copyright_string + 1);
+ more_printf(" Copyright : %s\n", hardware->sv->copyright_string);
}
struct cli_module_descr syslinux_show_modules = {
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 69a2b61f..76aed784 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -96,7 +96,7 @@ static void autocomplete_add_token_to_list(const char *token)
autocomplete_tail = new;
}
-static void autocomplete_destroy_list()
+static void autocomplete_destroy_list(void)
{
struct autocomplete_list *tmp = NULL;
@@ -727,7 +727,7 @@ out:
free(argv);
}
-static void reset_prompt()
+static void reset_prompt(void)
{
/* No need to display the prompt if we exit */
if (hdt_cli.mode != EXIT_MODE) {
@@ -779,7 +779,7 @@ void start_auto_mode(struct s_hardware *hardware)
more_printf("\n");
}
-void print_history()
+void print_history(void)
{
reset_more_printf();
for (int i = 1; i <= MAX_HISTORY_SIZE; i++) {
diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h
index 898b53f8..b55d108a 100644
--- a/com32/hdt/hdt-cli.h
+++ b/com32/hdt/hdt-cli.h
@@ -160,7 +160,7 @@ void start_auto_mode(struct s_hardware *hardware);
void main_show(char *item, struct s_hardware *hardware);
#define CLI_HISTORY "history"
-void print_history();
+void print_history(void);
// DMI STUFF
#define CLI_DMI_BASE_BOARD "base_board"
diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c
index 59175cec..736d9b6e 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -649,7 +649,7 @@ char *del_multi_spaces(char *p)
}
/* Reset the more_printf counter */
-void reset_more_printf()
+void reset_more_printf(void)
{
display_line_nb = 0;
}
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index d7a58e2f..0a0c8c4e 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -201,7 +201,7 @@ struct s_hardware {
char vesa_background[255];
};
-void reset_more_printf();
+void reset_more_printf(void);
const char *find_argument(const char **argv, const char *argument);
char *remove_spaces(char *p);
char *remove_trailing_lf(char *p);
diff --git a/com32/hdt/hdt-menu-syslinux.c b/com32/hdt/hdt-menu-syslinux.c
index c85bfbf4..02de5b31 100644
--- a/com32/hdt/hdt-menu-syslinux.c
+++ b/com32/hdt/hdt-menu-syslinux.c
@@ -51,9 +51,9 @@ void compute_syslinuxmenu(struct s_my_menu *menu, struct s_hardware *hardware)
menu->items_count++;
snprintf(buffer, sizeof buffer, "Version : %s",
- hardware->sv->version_string + 2);
+ hardware->sv->version_string);
snprintf(statbuffer, sizeof statbuffer, "Version: %s",
- hardware->sv->version_string + 2);
+ hardware->sv->version_string);
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu->items_count++;
@@ -71,10 +71,10 @@ void compute_syslinuxmenu(struct s_my_menu *menu, struct s_hardware *hardware)
add_item("", "", OPT_SEP, "", 0);
- snprintf(buffer, sizeof buffer, "%s", hardware->sv->copyright_string + 1);
+ snprintf(buffer, sizeof buffer, "%s", hardware->sv->copyright_string);
/* Remove the trailing LF in the copyright string to avoid scrolling */
snprintf(statbuffer, sizeof statbuffer, "%s",
- remove_trailing_lf(hardware->sv->copyright_string + 1));
+ remove_trailing_lf(hardware->sv->copyright_string));
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu->items_count++;
diff --git a/com32/hdt/hdt-menu.c b/com32/hdt/hdt-menu.c
index 1aa0906f..4629ee58 100644
--- a/com32/hdt/hdt-menu.c
+++ b/com32/hdt/hdt-menu.c
@@ -79,7 +79,7 @@ int start_menu_mode(struct s_hardware *hardware, char *version_string)
}
/* In the menu system, what to do on keyboard timeout */
-TIMEOUTCODE ontimeout()
+TIMEOUTCODE ontimeout(void)
{
// beep();
return CODE_WAIT;
diff --git a/com32/hdt/hdt-menu.h b/com32/hdt/hdt-menu.h
index f10e5290..c8c91243 100644
--- a/com32/hdt/hdt-menu.h
+++ b/com32/hdt/hdt-menu.h
@@ -82,7 +82,7 @@ struct s_hdt_menu {
int total_menu_count; // Sum of all menus we have
};
-TIMEOUTCODE ontimeout();
+TIMEOUTCODE ontimeout(void);
void keys_handler(t_menusystem * ms
__attribute__ ((unused)), t_menuitem * mi, int scancode);
diff --git a/com32/include/com32.h b/com32/include/com32.h
index aa7fb4b6..665fa0bf 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -95,12 +95,13 @@ typedef struct {
extern struct com32_sys_args {
uint32_t cs_sysargs;
char *cs_cmdline;
- void __cdecl(*cs_intcall) (uint8_t, const com32sys_t *, com32sys_t *);
+ void __cdecl (*cs_intcall)(uint8_t, const com32sys_t *, com32sys_t *);
void *cs_bounce;
uint32_t cs_bounce_size;
- void __cdecl(*cs_farcall) (uint32_t, const com32sys_t *, com32sys_t *);
- int __cdecl(*cs_cfarcall) (uint32_t, const void *, uint32_t);
+ void __cdecl (*cs_farcall)(uint32_t, const com32sys_t *, com32sys_t *);
+ int __cdecl (*cs_cfarcall)(uint32_t, const void *, uint32_t);
uint32_t cs_memsize;
+ const char *cs_name;
} __com32;
/*
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/include/syslinux/video.h b/com32/include/syslinux/video.h
index 737c742b..f22828aa 100644
--- a/com32/include/syslinux/video.h
+++ b/com32/include/syslinux/video.h
@@ -37,7 +37,7 @@
#include <stdint.h>
void syslinux_force_text_mode(void);
-int syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize);
-int syslinux_font_query(void **font);
+void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize);
+int syslinux_font_query(uint8_t **font);
#endif /* _SYSLINUX_API_H */
diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG
index 1eb18db1..1ae83bc7 100644
--- a/com32/lib/MCONFIG
+++ b/com32/lib/MCONFIG
@@ -24,7 +24,7 @@ REQFLAGS = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ \
-nostdinc -iwithprefix include -I. -I./sys -I../include
OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
-falign-labels=0 -ffast-math -fomit-frame-pointer
-WARNFLAGS = -W -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
+WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
LDFLAGS = -m elf32_i386
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index ad77bcd6..250c3962 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -64,10 +64,11 @@ LIBOBJS = \
sys/vesacon_write.o sys/vesaserial_write.o \
sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \
sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \
+ sys/vesa/i915resolution.o \
\
- pci/cfgtype.o pci/scan.o \
- pci/readb.o pci/readw.o pci/readl.o pci/readbios.o \
- pci/writeb.o pci/writew.o pci/writel.o pci/writebios.o \
+ pci/cfgtype.o pci/scan.o pci/bios.o \
+ pci/readb.o pci/readw.o pci/readl.o \
+ pci/writeb.o pci/writew.o pci/writel.o \
\
zlib/adler32.o zlib/compress.o zlib/crc32.o \
zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
@@ -108,9 +109,13 @@ 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
+ syslinux/setadv.o \
+ \
+ syslinux/video/fontquery.o syslinux/video/forcetext.o \
+ syslinux/video/reportmode.o
BINDIR = /usr/bin
LIBDIR = /usr/lib
diff --git a/com32/lib/chdir.c b/com32/lib/chdir.c
index 6f92d668..6a365f3b 100644
--- a/com32/lib/chdir.c
+++ b/com32/lib/chdir.c
@@ -8,6 +8,10 @@
int chdir(const char *path)
{
+ /* Actually implement something here... */
+
+ (void)path;
+
errno = ENOSYS;
return -1;
}
diff --git a/com32/lib/closedir.c b/com32/lib/closedir.c
index f8bbbabd..a2d11105 100644
--- a/com32/lib/closedir.c
+++ b/com32/lib/closedir.c
@@ -10,6 +10,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stdlib.h>
int closedir(DIR * dir)
{
diff --git a/com32/lib/fdopendir.c b/com32/lib/fdopendir.c
index 5fe11617..4fc31388 100644
--- a/com32/lib/fdopendir.c
+++ b/com32/lib/fdopendir.c
@@ -8,6 +8,8 @@
DIR *fdopendir(int __fd)
{
+ (void)__fd;
+
errno = ENOSYS;
return NULL;
}
diff --git a/com32/lib/libgcc/__moddi3.c b/com32/lib/libgcc/__moddi3.c
index ac8d3af7..4fc55884 100644
--- a/com32/lib/libgcc/__moddi3.c
+++ b/com32/lib/libgcc/__moddi3.c
@@ -21,7 +21,7 @@ int64_t __moddi3(int64_t num, int64_t den)
minus ^= 1;
}
- (void)__udivmoddi4(num, den, &v);
+ (void)__udivmoddi4(num, den, (uint64_t *)&v);
if (minus)
v = -v;
diff --git a/com32/lib/opendir.c b/com32/lib/opendir.c
index 6fc0f14f..21fe91d4 100644
--- a/com32/lib/opendir.c
+++ b/com32/lib/opendir.c
@@ -10,6 +10,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stdlib.h>
DIR *opendir(const char *pathname)
{
diff --git a/com32/lib/pci/readbios.c b/com32/lib/pci/bios.c
index f8ff3bff..b3c2c57d 100644
--- a/com32/lib/pci/readbios.c
+++ b/com32/lib/pci/bios.c
@@ -2,13 +2,15 @@
#include <string.h>
#include "pci/pci.h"
-uint32_t __pci_read_bios(uint32_t call, pciaddr_t a)
+uint32_t __pci_read_write_bios(uint32_t call, uint32_t v, pciaddr_t a)
{
com32sys_t rs;
memset(&rs, 0, sizeof rs);
rs.eax.w[0] = call;
rs.ebx.w[0] = a >> 8; /* bus:device:function */
rs.edi.b[0] = a; /* address:reg */
+ rs.ecx.l = v;
+ rs.eflags.l = EFLAGS_CF;
__intcall(0x1a, &rs, &rs);
return (rs.eflags.l & EFLAGS_CF) ? ~(uint32_t) 0 : rs.ecx.l;
diff --git a/com32/lib/pci/pci.h b/com32/lib/pci/pci.h
index 66a1eb50..8d81b0e4 100644
--- a/com32/lib/pci/pci.h
+++ b/com32/lib/pci/pci.h
@@ -10,7 +10,6 @@
#include <sys/cpu.h>
extern enum pci_config_type __pci_cfg_type;
-extern uint32_t __pci_read_bios(uint32_t call, pciaddr_t a);
-extern void __pci_write_bios(uint32_t call, uint32_t v, pciaddr_t a);
+extern uint32_t __pci_read_write_bios(uint32_t call, uint32_t v, pciaddr_t a);
#endif /* PCI_PCI_H */
diff --git a/com32/lib/pci/readx.c b/com32/lib/pci/readx.c
index f073eaa1..ed66d5b2 100644
--- a/com32/lib/pci/readx.c
+++ b/com32/lib/pci/readx.c
@@ -1,7 +1,7 @@
#include "pci/pci.h"
-#include <string.h>
-TYPE BWL(pci_read) (pciaddr_t a) {
+TYPE BWL(pci_read) (pciaddr_t a)
+{
TYPE r;
for (;;) {
@@ -42,7 +42,7 @@ TYPE BWL(pci_read) (pciaddr_t a) {
return r;
case PCI_CFG_BIOS:
- return (TYPE) __pci_read_bios(BIOSCALL, a);
+ return (TYPE) __pci_read_write_bios(BIOSCALL, 0, a);
default:
return (TYPE) ~ 0;
diff --git a/com32/lib/pci/writebios.c b/com32/lib/pci/writebios.c
deleted file mode 100644
index d367eee7..00000000
--- a/com32/lib/pci/writebios.c
+++ /dev/null
@@ -1,14 +0,0 @@
-#include <com32.h>
-#include <string.h>
-#include "pci/pci.h"
-
-void __pci_write_bios(uint32_t call, uint32_t v, pciaddr_t a)
-{
- com32sys_t rs;
- memset(&rs, 0, sizeof rs);
- rs.eax.w[0] = call;
- rs.ebx.w[0] = a >> 8; /* bus:device:function */
- rs.edi.b[0] = a; /* address:reg */
- rs.ecx.l = v;
- __intcall(0x1a, &rs, NULL);
-}
diff --git a/com32/lib/pci/writex.c b/com32/lib/pci/writex.c
index 14b20380..d83a1eed 100644
--- a/com32/lib/pci/writex.c
+++ b/com32/lib/pci/writex.c
@@ -1,6 +1,7 @@
#include "pci/pci.h"
-void BWL(pci_write) (TYPE v, pciaddr_t a) {
+void BWL(pci_write)(TYPE v, pciaddr_t a)
+{
for (;;) {
switch (__pci_cfg_type) {
case PCI_CFG_AUTO:
@@ -39,7 +40,7 @@ void BWL(pci_write) (TYPE v, pciaddr_t a) {
return;
case PCI_CFG_BIOS:
- __pci_write_bios(BIOSCALL, v, a);
+ __pci_read_write_bios(BIOSCALL, v, a);
return;
default:
diff --git a/com32/lib/readdir.c b/com32/lib/readdir.c
index 2ec7c7b3..3737d1ad 100644
--- a/com32/lib/readdir.c
+++ b/com32/lib/readdir.c
@@ -10,6 +10,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <stdlib.h>
struct dirent *readdir(DIR * dir)
{
@@ -28,8 +29,10 @@ struct dirent *readdir(DIR * dir)
__com32.cs_intcall(0x22, &regs, &regs);
- /* Don't do this as we won't be able to rewind.
+#if 0
+ /* Don't do this as we won't be able to rewind. */
dir->dd_fd = regs.esi.w[0]; /* Shouldn't be needed? */
+#endif
if ((!(regs.eflags.l & EFLAGS_CF)) && (regs.esi.w[0] != 0)) {
newde = calloc(1, sizeof(newde));
if (newde != NULL) {
diff --git a/com32/lib/strcasecmp.c b/com32/lib/strcasecmp.c
index 849c21fd..30949a09 100644
--- a/com32/lib/strcasecmp.c
+++ b/com32/lib/strcasecmp.c
@@ -7,7 +7,8 @@
int strcasecmp(const char *s1, const char *s2)
{
- const unsigned char *c1 = s1, *c2 = s2;
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
unsigned char ch;
int d = 0;
diff --git a/com32/lib/strcmp.c b/com32/lib/strcmp.c
index 77bb2b41..47a4aad8 100644
--- a/com32/lib/strcmp.c
+++ b/com32/lib/strcmp.c
@@ -6,7 +6,8 @@
int strcmp(const char *s1, const char *s2)
{
- const unsigned char *c1 = s1, *c2 = s2;
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
unsigned char ch;
int d = 0;
diff --git a/com32/lib/strncasecmp.c b/com32/lib/strncasecmp.c
index 8b8b967a..2caac0a5 100644
--- a/com32/lib/strncasecmp.c
+++ b/com32/lib/strncasecmp.c
@@ -7,7 +7,8 @@
int strncasecmp(const char *s1, const char *s2, size_t n)
{
- const unsigned char *c1 = s1, *c2 = s2;
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
unsigned char ch;
int d = 0;
diff --git a/com32/lib/strncmp.c b/com32/lib/strncmp.c
index f2f2f022..e41b9e36 100644
--- a/com32/lib/strncmp.c
+++ b/com32/lib/strncmp.c
@@ -6,7 +6,8 @@
int strncmp(const char *s1, const char *s2, size_t n)
{
- const unsigned char *c1 = s1, *c2 = s2;
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
unsigned char ch;
int d = 0;
diff --git a/com32/lib/sys/argv.c b/com32/lib/sys/argv.c
index b325f26d..3ff869b7 100644
--- a/com32/lib/sys/argv.c
+++ b/com32/lib/sys/argv.c
@@ -37,13 +37,14 @@
#include <stddef.h>
#include <stdio.h>
#include <syslinux/align.h>
+#include <com32.h>
extern char _end[]; /* Symbol created by linker */
void *__mem_end = &_end; /* Global variable for use by malloc() */
int __parse_argv(char ***argv, const char *str)
{
- char argv0[] = "";
+ char dummy_argv0[] = "";
char *mem = __mem_end;
const char *p = str;
char *q = mem;
@@ -75,9 +76,9 @@ int __parse_argv(char ***argv, const char *str)
}
/* Now create argv */
- arg = ALIGN_UP_FOR(q, char *);
+ arg = (char **)ALIGN_UP_FOR(q, char *);
*argv = arg;
- *arg++ = argv0; /* argv[0] */
+ *arg++ = __com32.cs_name ? __com32.cs_name : dummy_argv0; /* argv[0] */
q--; /* Point q to final null */
if (mem < q)
diff --git a/com32/lib/sys/colortable.c b/com32/lib/sys/colortable.c
index df6d9782..ab1c4246 100644
--- a/com32/lib/sys/colortable.c
+++ b/com32/lib/sys/colortable.c
@@ -4,6 +4,6 @@ static struct color_table default_color_table[] = {
{"default", "0", 0xffffffff, 0x00000000, SHADOW_NORMAL}
};
-struct color_table *console_color_table = &default_color_table;
+struct color_table *console_color_table = default_color_table;
int console_color_table_size =
(sizeof default_color_table / sizeof(struct color_table));
diff --git a/com32/lib/sys/entry.S b/com32/lib/sys/entry.S
index 53bf2ecb..c34dbdf4 100644
--- a/com32/lib/sys/entry.S
+++ b/com32/lib/sys/entry.S
@@ -30,7 +30,7 @@
*/
/* Number of arguments in our version of the entry structure */
-#define COM32_ARGS 7
+#define COM32_ARGS 8
.section ".init","ax"
.globl _start
diff --git a/com32/lib/sys/libansi.c b/com32/lib/sys/libansi.c
index 5bc0026e..a011cb87 100644
--- a/com32/lib/sys/libansi.c
+++ b/com32/lib/sys/libansi.c
@@ -46,18 +46,21 @@ void display_cursor(bool status)
}
}
-void clear_end_of_line() {
+void clear_end_of_line(void)
+{
fputs(CSI "0K", stdout);
}
-void move_cursor_left(int count) {
+void move_cursor_left(int count)
+{
char buffer[10];
memset(buffer,0,sizeof(buffer));
sprintf(buffer,CSI "%dD",count);
fputs(buffer, stdout);
}
-void move_cursor_right(int count) {
+void move_cursor_right(int count)
+{
char buffer[10];
memset(buffer,0,sizeof(buffer));
sprintf(buffer, CSI "%dC", count);
@@ -71,38 +74,45 @@ void set_cursor_blink(bool status) {
fputs("\033[0m",stdout);
}
-void clear_line() {
+void clear_line(void)
+{
fputs(CSI "2K", stdout);
}
-void clear_beginning_of_line() {
+void clear_beginning_of_line(void)
+{
fputs(CSI "1K", stdout);
}
-void move_cursor_to_column(int count) {
+void move_cursor_to_column(int count)
+{
char buffer[10];
memset(buffer,0,sizeof(buffer));
sprintf(buffer, CSI "%dG", count);
fputs(buffer, stdout);
}
-void move_cursor_to_next_line() {
+void move_cursor_to_next_line(void)
+{
fputs("\033e", stdout);
}
-void disable_utf8() {
+void disable_utf8(void)
+{
fputs("\033%@", stdout);
}
-void set_g1_special_char(){
+void set_g1_special_char(void){
fputs("\033)0", stdout);
}
-void set_us_g0_charset() {
+void set_us_g0_charset(void)
+{
fputs("\033(B\1#0", stdout);
}
-void clear_entire_screen() {
+void clear_entire_screen(void)
+{
fputs(CSI "2J", stdout);
}
@@ -186,7 +196,7 @@ void cls(void)
cprint_vga2ansi('0', '0');
}
-void reset_colors()
+void reset_colors(void)
{
csprint(CSI "1D", 0x07);
}
diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c
index 256c8247..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;
@@ -217,18 +245,25 @@ err:
int vesacon_default_background(void)
{
int x, y, dx, dy, dy2;
- uint8_t *bgptr = (uint8_t *) & __vesacon_background;
+ int z;
+ unsigned int shft;
+ uint8_t *bgptr = (uint8_t *)__vesacon_background;
uint8_t k;
if (__vesacon_pixel_format == PXF_NONE)
return 0; /* Not in graphics mode */
- for (y = 0, dy = -__vesa_info.mi.v_res / 2;
+ z = max(__vesa_info.mi.v_res, __vesa_info.mi.h_res) >> 1;
+ z = ((z*z) >> 11) - 1;
+ asm("bsrl %1,%0" : "=r" (shft) : "rm" (z));
+ shft++;
+
+ for (y = 0, dy = -(__vesa_info.mi.v_res >> 1);
y < __vesa_info.mi.v_res; y++, dy++) {
dy2 = dy * dy;
- for (x = 0, dx = -__vesa_info.mi.h_res / 2;
+ for (x = 0, dx = -(__vesa_info.mi.h_res >> 1);
x < __vesa_info.mi.h_res; x++, dx++) {
- k = __vesacon_linear_to_srgb[500 + ((dx * dx + dy2) >> 6)];
+ k = __vesacon_linear_to_srgb[500 + ((dx*dx + dy2) >> shft)];
bgptr[0] = k; /* Blue */
bgptr[1] = k; /* Green */
bgptr[2] = k; /* Red */
diff --git a/com32/lib/sys/vesa/i915resolution.c b/com32/lib/sys/vesa/i915resolution.c
new file mode 100644
index 00000000..6ebb04d3
--- /dev/null
+++ b/com32/lib/sys/vesa/i915resolution.c
@@ -0,0 +1,795 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Based on:
+ *
+ * 915 resolution by steve tomljenovic
+ *
+ * This was tested only on Sony VGN-FS550. Use at your own risk
+ *
+ * This code is based on the techniques used in :
+ *
+ * - 855patch. Many thanks to Christian Zietz (czietz gmx net)
+ * for demonstrating how to shadow the VBIOS into system RAM
+ * and then modify it.
+ *
+ * - 1280patch by Andrew Tipton (andrewtipton null li).
+ *
+ * - 855resolution by Alain Poirier
+ *
+ * This source code is into the public domain.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#define __USE_GNU
+#include <string.h>
+#include <sys/io.h>
+#include <sys/cpu.h>
+#include <sys/pci.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdbool.h>
+#include "video.h"
+#include "debug.h"
+
+#define VBIOS_START 0xc0000
+#define VBIOS_SIZE 0x10000
+
+#define MODE_TABLE_OFFSET_845G 617
+
+#define VERSION "0.5.3"
+
+#define ATI_SIGNATURE1 "ATI MOBILITY RADEON"
+#define ATI_SIGNATURE2 "ATI Technologies Inc"
+#define NVIDIA_SIGNATURE "NVIDIA Corp"
+#define INTEL_SIGNATURE "Intel Corp"
+
+typedef unsigned char * address;
+
+typedef enum {
+ CT_UNKWN, CT_830, CT_845G, CT_855GM, CT_865G, CT_915G, CT_915GM,
+ CT_945G, CT_945GM, CT_946GZ, CT_G965, CT_Q965, CT_945GME,
+ CHIPSET_TYPES
+} chipset_type;
+
+typedef enum {
+ BT_UNKWN, BT_1, BT_2, BT_3
+} bios_type;
+
+static int freqs[] = { 60, 75, 85 };
+
+typedef struct {
+ uint8_t mode;
+ uint8_t bits_per_pixel;
+ uint16_t resolution;
+ uint8_t unknown;
+} __attribute__((packed)) vbios_mode;
+
+typedef struct {
+ uint16_t clock; /* Clock frequency in 10 kHz */
+ uint8_t x1;
+ uint8_t x_total;
+ uint8_t x2;
+ uint8_t y1;
+ uint8_t y_total;
+ uint8_t y2;
+} __attribute__((packed)) vbios_resolution_type1;
+
+typedef struct {
+ uint32_t clock;
+
+ uint16_t x1;
+ uint16_t htotal;
+ uint16_t x2;
+ uint16_t hblank;
+ uint16_t hsyncstart;
+ uint16_t hsyncend;
+
+ uint16_t y1;
+ uint16_t vtotal;
+ uint16_t y2;
+ uint16_t vblank;
+ uint16_t vsyncstart;
+ uint16_t vsyncend;
+} __attribute__((packed)) vbios_modeline_type2;
+
+typedef struct {
+ uint8_t xchars;
+ uint8_t ychars;
+ uint8_t unknown[4];
+
+ vbios_modeline_type2 modelines[];
+} __attribute__((packed)) vbios_resolution_type2;
+
+typedef struct {
+ uint32_t clock;
+
+ uint16_t x1;
+ uint16_t htotal;
+ uint16_t x2;
+ uint16_t hblank;
+ uint16_t hsyncstart;
+ uint16_t hsyncend;
+
+ uint16_t y1;
+ uint16_t vtotal;
+ uint16_t y2;
+ uint16_t vblank;
+ uint16_t vsyncstart;
+ uint16_t vsyncend;
+
+ uint16_t timing_h;
+ uint16_t timing_v;
+
+ uint8_t unknown[6];
+} __attribute__((packed)) vbios_modeline_type3;
+
+typedef struct {
+ unsigned char unknown[6];
+
+ vbios_modeline_type3 modelines[];
+} __attribute__((packed)) vbios_resolution_type3;
+
+
+typedef struct {
+ unsigned int chipset_id;
+ chipset_type chipset;
+ bios_type bios;
+
+ address bios_ptr;
+
+ vbios_mode * mode_table;
+ unsigned int mode_table_size;
+
+ uint8_t b1, b2;
+
+ bool unlocked;
+} vbios_map;
+
+#if 0 /* Debugging hacks */
+static void good_marker(int x)
+{
+ ((uint16_t *)0xb8000)[x] = 0x2f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void bad_marker(int x)
+{
+ ((uint16_t *)0xb8000)[x] = 0x4f30 - ((x & 0xf0) << 4) + (x & 0x0f);
+}
+
+static void status(const char *fmt, ...)
+{
+ va_list ap;
+ char msg[81], *p;
+ int i;
+ uint16_t *q;
+
+ memset(msg, 0, sizeof msg);
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof msg, fmt, ap);
+ va_end(ap);
+ p = msg;
+ q = (uint16_t *)0xb8000 + 80;
+ for (i = 0; i < 80; i++)
+ *q++ = *p++ + 0x1f00;
+}
+#else
+static inline void good_marker(int x) { (void)x; }
+static inline void bad_marker(int x) { (void)x; }
+static inline void status(const char *fmt, ...) { (void)fmt; }
+#endif
+
+static unsigned int get_chipset_id(void) {
+ return pci_readl(0x80000000);
+}
+
+static chipset_type get_chipset(unsigned int id) {
+ chipset_type type;
+
+ switch (id) {
+ case 0x35758086:
+ type = CT_830;
+ break;
+
+ case 0x25608086:
+ type = CT_845G;
+ break;
+
+ case 0x35808086:
+ type = CT_855GM;
+ break;
+
+ case 0x25708086:
+ type = CT_865G;
+ break;
+
+ case 0x25808086:
+ type = CT_915G;
+ break;
+
+ case 0x25908086:
+ type = CT_915GM;
+ break;
+
+ case 0x27708086:
+ type = CT_945G;
+ break;
+
+ case 0x27a08086:
+ type = CT_945GM;
+ break;
+
+ case 0x29708086:
+ type = CT_946GZ;
+ break;
+
+ case 0x29a08086:
+ type = CT_G965;
+ break;
+
+ case 0x29908086:
+ type = CT_Q965;
+ break;
+
+ case 0x27ac8086:
+ type = CT_945GME;
+ break;
+
+ default:
+ type = CT_UNKWN;
+ break;
+ }
+
+ return type;
+}
+
+
+static vbios_resolution_type1 * map_type1_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res));
+ return ptr;
+}
+
+static vbios_resolution_type2 * map_type2_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res));
+ return ptr;
+}
+
+static vbios_resolution_type3 * map_type3_resolution(vbios_map * map,
+ uint16_t res)
+{
+ vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res));
+ return ptr;
+}
+
+
+static bool detect_bios_type(vbios_map * map, int entry_size)
+{
+ unsigned int i;
+ uint16_t r1, r2;
+
+ r1 = r2 = 32000;
+
+ for (i = 0; i < map->mode_table_size; i++) {
+ if (map->mode_table[i].resolution <= r1) {
+ r1 = map->mode_table[i].resolution;
+ } else if (map->mode_table[i].resolution <= r2) {
+ r2 = map->mode_table[i].resolution;
+ }
+ }
+
+ return ((r2-r1-6) % entry_size) == 0;
+}
+
+static inline void close_vbios(vbios_map *map)
+{
+ (void)map;
+}
+
+static vbios_map * open_vbios(void)
+{
+ static vbios_map _map;
+ vbios_map * const map = &_map;
+
+ memset(&_map, 0, sizeof _map);
+
+ /*
+ * Determine chipset
+ */
+ map->chipset_id = get_chipset_id();
+ good_marker(0x10);
+ map->chipset = get_chipset(map->chipset_id);
+ good_marker(0x11);
+
+ /*
+ * Map the video bios to memory
+ */
+ map->bios_ptr = (void *)VBIOS_START;
+
+ /*
+ * check if we have ATI Radeon
+ */
+
+ if (memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE1, strlen(ATI_SIGNATURE1)) ||
+ memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE2, strlen(ATI_SIGNATURE2)) ) {
+ debug("ATI chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+ return NULL;
+ }
+
+ /*
+ * check if we have NVIDIA
+ */
+
+ if (memmem(map->bios_ptr, VBIOS_SIZE, NVIDIA_SIGNATURE, strlen(NVIDIA_SIGNATURE))) {
+ debug("NVIDIA chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+ return NULL;
+ }
+
+ /*
+ * check if we have Intel
+ */
+
+ if (map->chipset == CT_UNKWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) {
+ debug("Intel chipset detected. However, 915resolution was unable to determine the chipset type.\r\n");
+
+ debug("Chipset Id: %x\r\n", map->chipset_id);
+
+ debug("Please report this problem to stomljen@yahoo.com\r\n");
+
+ close_vbios(map);
+ return NULL;
+ }
+
+ /*
+ * check for others
+ */
+
+ if (map->chipset == CT_UNKWN) {
+ debug("Unknown chipset type and unrecognized bios.\r\n");
+ debug("915resolution only works with Intel 800/900 series graphic chipsets.\r\n");
+
+ debug("Chipset Id: %x\r\n", map->chipset_id);
+ close_vbios(map);
+ return NULL;
+ }
+
+ /*
+ * Figure out where the mode table is
+ */
+ good_marker(0x12);
+
+ {
+ address p = map->bios_ptr + 16;
+ address limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode));
+
+ while (p < limit && map->mode_table == 0) {
+ vbios_mode * mode_ptr = (vbios_mode *) p;
+
+ if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) &&
+ ((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30)) {
+
+ map->mode_table = mode_ptr;
+ }
+
+ p++;
+ }
+
+ if (map->mode_table == 0) {
+ debug("Unable to locate the mode table.\r\n");
+ close_vbios(map);
+ return NULL;
+ }
+ }
+ good_marker(0x13);
+
+ /*
+ * Determine size of mode table
+ */
+
+ {
+ vbios_mode * mode_ptr = map->mode_table;
+
+ while (mode_ptr->mode != 0xff) {
+ map->mode_table_size++;
+ mode_ptr++;
+ }
+ }
+ good_marker(0x14);
+ status("mode_table_size = %d", map->mode_table_size);
+
+ /*
+ * Figure out what type of bios we have
+ * order of detection is important
+ */
+
+ if (detect_bios_type(map, sizeof(vbios_modeline_type3))) {
+ map->bios = BT_3;
+ }
+ else if (detect_bios_type(map, sizeof(vbios_modeline_type2))) {
+ map->bios = BT_2;
+ }
+ else if (detect_bios_type(map, sizeof(vbios_resolution_type1))) {
+ map->bios = BT_1;
+ }
+ else {
+ debug("Unable to determine bios type.\r\n");
+ debug("Mode Table Offset: $C0000 + $%x\r\n", ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+ debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+ bad_marker(0x15);
+ return NULL;
+ }
+ good_marker(0x15);
+
+ return map;
+}
+
+static void unlock_vbios(vbios_map * map)
+{
+ assert(!map->unlocked);
+
+ map->unlocked = true;
+
+ switch (map->chipset) {
+ case CT_UNKWN:
+ case CHIPSET_TYPES: /* Shut up gcc */
+ break;
+ case CT_830:
+ case CT_855GM:
+ map->b1 = pci_readb(0x8000005a);
+ pci_writeb(0x33, 0x8000005a);
+ break;
+ case CT_845G:
+ case CT_865G:
+ case CT_915G:
+ case CT_915GM:
+ case CT_945G:
+ case CT_945GM:
+ case CT_945GME:
+ case CT_946GZ:
+ case CT_G965:
+ case CT_Q965:
+ map->b1 = pci_readb(0x80000091);
+ map->b2 = pci_readb(0x80000092);
+ pci_writeb(0x33, 0x80000091);
+ pci_writeb(0x33, 0x80000092);
+ break;
+ }
+
+#if DEBUG
+ {
+ unsigned int t = inl(0xcfc);
+ debug("unlock PAM: (0x%08x)\r\n", t);
+ }
+#endif
+}
+
+static void relock_vbios(vbios_map * map)
+{
+ assert(map->unlocked);
+ map->unlocked = false;
+
+ switch (map->chipset) {
+ case CT_UNKWN:
+ case CHIPSET_TYPES: /* Shut up gcc */
+ break;
+ case CT_830:
+ case CT_855GM:
+ pci_writeb(map->b1, 0x8000005a);
+ break;
+ case CT_845G:
+ case CT_865G:
+ case CT_915G:
+ case CT_915GM:
+ case CT_945G:
+ case CT_945GM:
+ case CT_945GME:
+ case CT_946GZ:
+ case CT_G965:
+ case CT_Q965:
+ pci_writeb(map->b1, 0x80000091);
+ pci_writeb(map->b2, 0x80000092);
+ break;
+ }
+
+#if DEBUG
+ {
+ unsigned int t = inl(0xcfc);
+ debug("relock PAM: (0x%08x)\r\n", t);
+ }
+#endif
+}
+
+#if 0
+static void list_modes(vbios_map *map, unsigned int raw)
+{
+ unsigned int i, x, y;
+
+ for (i=0; i < map->mode_table_size; i++) {
+ switch(map->bios) {
+ case BT_1:
+ {
+ vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+
+ x = ((((unsigned int) res->x2) & 0xf0) << 4) | res->x1;
+ y = ((((unsigned int) res->y2) & 0xf0) << 4) | res->y1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+
+ if (raw)
+ {
+ debug("Mode %02x (raw) :\r\n\t%02x %02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n", map->mode_table[i].mode, res->unknow1[0],res->unknow1[1], res->x1,res->x_total,res->x2,res->y1,res->y_total,res->y2);
+ }
+
+ }
+ break;
+ case BT_2:
+ {
+ vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+
+ x = res->modelines[0].x1+1;
+ y = res->modelines[0].y1+1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+ }
+ break;
+ case BT_3:
+ {
+ vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+
+ x = res->modelines[0].x1+1;
+ y = res->modelines[0].y1+1;
+
+ if (x != 0 && y != 0) {
+ debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel);
+ }
+ }
+ break;
+ case BT_UNKWN:
+ break;
+ }
+ }
+}
+#endif
+
+static void gtf_timings(int x, int y, int freq, uint32_t *clock,
+ uint16_t *hsyncstart, uint16_t *hsyncend, uint16_t *hblank,
+ uint16_t *vsyncstart, uint16_t *vsyncend, uint16_t *vblank)
+{
+ int hbl, vbl, vfreq;
+
+ vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5;
+ vfreq = vbl * freq;
+ hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) /
+ (70.0 + 300000.0 / vfreq) / 16.0 + 0.5);
+
+ *vsyncstart = y;
+ *vsyncend = y + 3;
+ *vblank = vbl - 1;
+ *hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1;
+ *hsyncend = x + hbl / 2 - 1;
+ *hblank = x + hbl - 1;
+ *clock = (x + hbl) * vfreq / 1000;
+}
+
+static int set_mode(vbios_map * map, unsigned int mode,
+ unsigned int x, unsigned int y, unsigned int bp,
+ unsigned int htotal, unsigned int vtotal)
+{
+ int xprev, yprev;
+ unsigned int i, j;
+ int rv = -1;
+
+ for (i=0; i < map->mode_table_size; i++) {
+ if (map->mode_table[i].mode == mode) {
+ switch(map->bios) {
+ case BT_1:
+ {
+ vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
+ uint32_t clock;
+ uint16_t hsyncstart, hsyncend, hblank;
+ uint16_t vsyncstart, vsyncend, vblank;
+
+ if (bp) {
+ map->mode_table[i].bits_per_pixel = bp;
+ }
+
+ gtf_timings(x, y, freqs[0], &clock,
+ &hsyncstart, &hsyncend, &hblank,
+ &vsyncstart, &vsyncend, &vblank);
+
+ status("x = %d, y = %d, clock = %lu, h = %d %d %d, v = %d %d %d\n",
+ x, y, clock,
+ hsyncstart, hsyncend, hblank,
+ vsyncstart, vsyncend, vblank);
+
+ htotal = htotal ? htotal : (unsigned int)hblank+1;
+ vtotal = vtotal ? vtotal : (unsigned int)vblank+1;
+
+ res->clock = clock/10; /* Units appear to be 10 kHz */
+ res->x2 = (((htotal-x) >> 8) & 0x0f) | ((x >> 4) & 0xf0);
+ res->x1 = (x & 0xff);
+
+ res->y2 = (((vtotal-y) >> 8) & 0x0f) | ((y >> 4) & 0xf0);
+ res->y1 = (y & 0xff);
+ if (htotal)
+ res->x_total = ((htotal-x) & 0xff);
+
+ if (vtotal)
+ res->y_total = ((vtotal-y) & 0xff);
+
+ rv = 0;
+ }
+ break;
+ case BT_2:
+ {
+ vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
+
+ res->xchars = x / 8;
+ res->ychars = y / 16 - 1;
+ xprev = res->modelines[0].x1;
+ yprev = res->modelines[0].y1;
+
+ for(j=0; j < 3; j++) {
+ vbios_modeline_type2 * modeline = &res->modelines[j];
+
+ if (modeline->x1 == xprev && modeline->y1 == yprev) {
+ modeline->x1 = modeline->x2 = x-1;
+ modeline->y1 = modeline->y2 = y-1;
+
+ gtf_timings(x, y, freqs[j], &modeline->clock,
+ &modeline->hsyncstart, &modeline->hsyncend,
+ &modeline->hblank, &modeline->vsyncstart,
+ &modeline->vsyncend, &modeline->vblank);
+
+ if (htotal)
+ modeline->htotal = htotal;
+ else
+ modeline->htotal = modeline->hblank;
+
+ if (vtotal)
+ modeline->vtotal = vtotal;
+ else
+ modeline->vtotal = modeline->vblank;
+ }
+ }
+
+ rv = 0;
+ }
+ break;
+ case BT_3:
+ {
+ vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
+
+ xprev = res->modelines[0].x1;
+ yprev = res->modelines[0].y1;
+
+ for (j=0; j < 3; j++) {
+ vbios_modeline_type3 * modeline = &res->modelines[j];
+
+ if (modeline->x1 == xprev && modeline->y1 == yprev) {
+ modeline->x1 = modeline->x2 = x-1;
+ modeline->y1 = modeline->y2 = y-1;
+
+ gtf_timings(x, y, freqs[j], &modeline->clock,
+ &modeline->hsyncstart, &modeline->hsyncend,
+ &modeline->hblank, &modeline->vsyncstart,
+ &modeline->vsyncend, &modeline->vblank);
+ if (htotal)
+ modeline->htotal = htotal;
+ else
+ modeline->htotal = modeline->hblank;
+ if (vtotal)
+ modeline->vtotal = vtotal;
+ else
+ modeline->vtotal = modeline->vblank;
+
+ modeline->timing_h = y-1;
+ modeline->timing_v = x-1;
+ }
+ }
+
+ rv = 0;
+ }
+ break;
+ case BT_UNKWN:
+ break;
+ }
+ }
+ }
+
+ return rv;
+}
+
+static inline void display_map_info(vbios_map * map) {
+#ifdef DEBUG
+ static const char * bios_type_names[] =
+ {"UNKNOWN", "TYPE 1", "TYPE 2", "TYPE 3"};
+ static const char * chipset_type_names[] = {
+ "UNKNOWN", "830", "845G", "855GM", "865G", "915G", "915GM", "945G",
+ "945GM", "946GZ", "G965", "Q965", "945GME"
+ };
+
+ debug("Chipset: %s\r\n", chipset_type_names[map->chipset]);
+ debug("BIOS: %s\r\n", bios_type_names[map->bios]);
+
+ debug("Mode Table Offset: $C0000 + $%x\r\n",
+ ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr));
+ debug("Mode Table Entries: %u\r\n", map->mode_table_size);
+#endif
+ (void)map;
+}
+
+int __vesacon_i915resolution(int x, int y)
+{
+ vbios_map * map;
+ unsigned int mode = 0x52; /* 800x600x32 mode in known BIOSes */
+ unsigned int bp = 32; /* 32 bits per pixel */
+ int rv = 0;
+
+ good_marker(0);
+
+ map = open_vbios();
+ if (!map)
+ return -1;
+
+ good_marker(1);
+
+ display_map_info(map);
+
+ debug("\r\n");
+
+ if (mode && x && y) {
+ good_marker(2);
+ cli();
+ good_marker(3);
+ unlock_vbios(map);
+ good_marker(4);
+ rv = set_mode(map, mode, x, y, bp, 0, 0);
+ if (rv)
+ bad_marker(5);
+ else
+ good_marker(5);
+ relock_vbios(map);
+ good_marker(6);
+ sti();
+
+ debug("Patch mode %02x to resolution %dx%d complete\r\n", mode, x, y);
+ }
+ close_vbios(map);
+
+ return rv;
+}
diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c
index 0221fcf7..0a436f4c 100644
--- a/com32/lib/sys/vesa/initvesa.c
+++ b/com32/lib/sys/vesa/initvesa.c
@@ -37,6 +37,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/fpu.h>
+#include <syslinux/video.h>
#include "vesa.h"
#include "video.h"
#include "fill.h"
@@ -240,12 +241,10 @@ static int vesacon_set_mode(int x, int y)
__vesacon_format_pixels = __vesacon_format_pixels_list[bestpxf];
/* Download the SYSLINUX- or BIOS-provided font */
- rm.eax.w[0] = 0x0018; /* Query custom font */
- __intcall(0x22, &rm, &rm);
- if (!(rm.eflags.l & EFLAGS_CF) && rm.eax.b[0]) {
- __vesacon_font_height = rm.eax.b[0];
- rom_font = MK_PTR(rm.es, rm.ebx.w[0]);
- } else {
+ __vesacon_font_height = syslinux_font_query(&rom_font);
+ if (!__vesacon_font_height) {
+ /* Get BIOS 8x16 font */
+
rm.eax.w[0] = 0x1130; /* Get Font Information */
rm.ebx.w[0] = 0x0600; /* Get 8x16 ROM font */
__intcall(0x10, &rm, &rm);
@@ -270,17 +269,13 @@ static int vesacon_set_mode(int x, int y)
__vesacon_init_copy_to_screen();
/* Tell syslinux we changed video mode */
- rm.eax.w[0] = 0x0017; /* Report video mode change */
/* In theory this should be:
- rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+ flags = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
However, that would assume all systems that claim to handle text
output in VESA modes actually do that... */
- rm.ebx.w[0] = 0x000f;
- rm.ecx.w[0] = mi->h_res;
- rm.edx.w[0] = mi->v_res;
- __intcall(0x22, &rm, NULL);
+ syslinux_report_video_mode(0x000f, mi->h_res, mi->v_res);
__vesacon_pixel_format = bestpxf;
@@ -323,8 +318,13 @@ int __vesacon_init(int x, int y)
return 10;
rv = vesacon_set_mode(x, y);
- if (rv)
- return rv;
+ if (rv) {
+ /* Try to see if we can just patch the BIOS... */
+ if (__vesacon_i915resolution(x, y))
+ return rv;
+ if (vesacon_set_mode(x, y))
+ return rv;
+ }
init_text_display();
diff --git a/com32/lib/sys/vesa/screencpy.c b/com32/lib/sys/vesa/screencpy.c
index b66e8854..9740ea14 100644
--- a/com32/lib/sys/vesa/screencpy.c
+++ b/com32/lib/sys/vesa/screencpy.c
@@ -43,7 +43,7 @@ static struct win_info {
static inline int __constfunc ilog2(unsigned int x)
{
-asm("bsrl %1,%0": "=r"(x):"rm"(x));
+ asm("bsrl %1,%0" : "=r"(x) : "rm"(x));
return x;
}
diff --git a/com32/lib/sys/vesa/video.h b/com32/lib/sys/vesa/video.h
index 764228a0..d14494b1 100644
--- a/com32/lib/sys/vesa/video.h
+++ b/com32/lib/sys/vesa/video.h
@@ -92,4 +92,6 @@ void __vesacon_set_cursor(int, int, bool);
void __vesacon_copy_to_screen(size_t, const uint32_t *, size_t);
void __vesacon_init_copy_to_screen(void);
+int __vesacon_i915resolution(int x, int y);
+
#endif /* LIB_SYS_VESA_VIDEO_H */
diff --git a/com32/lib/sys/vesaserial_write.c b/com32/lib/sys/vesaserial_write.c
index 47527c3a..775ca19e 100644
--- a/com32/lib/sys/vesaserial_write.c
+++ b/com32/lib/sys/vesaserial_write.c
@@ -38,7 +38,7 @@
#include <console.h>
#include "file.h"
-extern int __vesacon_open(void);
+extern int __vesacon_open(struct file_info *);
extern int __vesacon_close(struct file_info *);
extern ssize_t __vesacon_write(struct file_info *, const void *, size_t);
extern ssize_t __xserial_write(struct file_info *, const void *, size_t);
diff --git a/com32/lib/syslinux/getadv.c b/com32/lib/syslinux/getadv.c
index 456084b0..5578313e 100644
--- a/com32/lib/syslinux/getadv.c
+++ b/com32/lib/syslinux/getadv.c
@@ -39,7 +39,7 @@
const void *syslinux_getadv(int tag, size_t * size)
{
const uint8_t *p;
- size_t left, len;
+ size_t left;
p = syslinux_adv_ptr();
left = syslinux_adv_size();
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index db985163..df793625 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -253,6 +253,9 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
case 'n': /* "normal" */
video_mode = 0xffff;
break;
+ case 'c': /* "current" */
+ video_mode = 0x0f04;
+ break;
default:
video_mode = strtoul(arg, NULL, 0);
break;
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/lib/syslinux/video/fontquery.c b/com32/lib/syslinux/video/fontquery.c
new file mode 100644
index 00000000..dd5d86e3
--- /dev/null
+++ b/com32/lib/syslinux/video/fontquery.c
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/video/forcetext.c
+ */
+
+#include <syslinux/video.h>
+#include <com32.h>
+
+/*
+ * Returns height of font or zero if no custom font loaded
+ */
+int syslinux_font_query(uint8_t **font)
+{
+ static com32sys_t ireg;
+ com32sys_t oreg;
+ int height;
+
+ ireg.eax.w[0] = 0x0018;
+ __intcall(0x22, &ireg, &oreg);
+
+ height = !(oreg.eflags.l & EFLAGS_CF) ? oreg.eax.b[0] : 0;
+ if (height)
+ *font = MK_PTR(oreg.es, oreg.ebx.w[0]);
+
+ return height;
+}
+
diff --git a/com32/lib/syslinux/video/forcetext.c b/com32/lib/syslinux/video/forcetext.c
new file mode 100644
index 00000000..136cb279
--- /dev/null
+++ b/com32/lib/syslinux/video/forcetext.c
@@ -0,0 +1,42 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/video/forcetext.c
+ */
+
+#include <syslinux/video.h>
+#include <com32.h>
+
+void syslinux_force_text_mode(void)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0005;
+ __intcall(0x22, &ireg, NULL);
+}
diff --git a/com32/lib/syslinux/video/reportmode.c b/com32/lib/syslinux/video/reportmode.c
new file mode 100644
index 00000000..57fd6fdc
--- /dev/null
+++ b/com32/lib/syslinux/video/reportmode.c
@@ -0,0 +1,45 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/video/reportmode.c
+ */
+
+#include <syslinux/video.h>
+#include <com32.h>
+
+void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0017;
+ ireg.ebx.w[0] = flags;
+ ireg.ecx.w[0] = xsize;
+ ireg.edx.w[0] = ysize;
+ __intcall(0x22, &ireg, NULL);
+}
diff --git a/com32/lib/zlib/crc32.c b/com32/lib/zlib/crc32.c
index 447f138e..67e6f31e 100644
--- a/com32/lib/zlib/crc32.c
+++ b/com32/lib/zlib/crc32.c
@@ -100,7 +100,7 @@ local void make_crc_table()
/* make exclusive-or pattern from polynomial (0xedb88320UL) */
poly = 0UL;
- for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
poly |= 1UL << (31 - p[n]);
/* generate a crc for every 8-bit value */
diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile
index c1ac76fb..7e6c2e96 100644
--- a/com32/mboot/Makefile
+++ b/com32/mboot/Makefile
@@ -24,7 +24,7 @@ LNXLIBS = ../libutil/libutil_lnx.a
MODULES = mboot.c32
TESTFILES =
-OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o
+OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o syslinux.o
all: $(MODULES) $(TESTFILES)
diff --git a/com32/mboot/map.c b/com32/mboot/map.c
index a32f9b3b..267e50c8 100644
--- a/com32/mboot/map.c
+++ b/com32/mboot/map.c
@@ -151,6 +151,10 @@ struct multiboot_header *map_image(void *ptr, size_t len)
!eh->e_phnum || eh->e_phoff + eh->e_phentsize * eh->e_phnum > len)
eh = NULL; /* No valid ELF header found */
+ /* Is this a Solaris kernel? */
+ if (!set.solaris && eh && kernel_is_solaris(eh))
+ opt.solaris = true;
+
/*
* Note: the Multiboot Specification implies that AOUT_KLUDGE should
* have precedence over the ELF header. However, Grub disagrees, and
diff --git a/com32/mboot/mboot.c b/com32/mboot/mboot.c
index 8425e068..915c7857 100644
--- a/com32/mboot/mboot.c
+++ b/com32/mboot/mboot.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -36,7 +36,7 @@
struct multiboot_info mbinfo;
struct syslinux_pm_regs regs;
-struct my_options opt;
+struct my_options opt, set;
struct module_data {
void *data;
@@ -161,11 +161,21 @@ int main(int argc, char *argv[])
argv++;
while (*argv) {
- if (!strcmp(*argv, "-solaris"))
- opt.solaris = true;
- else if (!strcmp(*argv, "-aout"))
- opt.aout = true;
- else
+ bool v = true;
+ const char *p = *argv;
+
+ if (!memcmp(p, "-no", 3)) {
+ v = false;
+ p += 3;
+ }
+
+ if (!strcmp(p, "-solaris")) {
+ opt.solaris = v;
+ set.solaris = true;
+ } else if (!strcmp(p, "-aout")) {
+ opt.aout = v;
+ set.aout = true;
+ } else
break;
argv++;
}
@@ -222,6 +232,8 @@ int main(int argc, char *argv[])
/* Add auxilliary information */
mboot_make_memmap();
mboot_apm();
+ mboot_syslinux_info();
+
if (opt.solaris)
mboot_solaris_dhcp_hack();
diff --git a/com32/mboot/mboot.h b/com32/mboot/mboot.h
index 993b31a8..b646cd36 100644
--- a/com32/mboot/mboot.h
+++ b/com32/mboot/mboot.h
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -50,6 +50,7 @@
#include <syslinux/loadfile.h>
#include <syslinux/movebits.h>
#include <syslinux/bootpm.h>
+#include <syslinux/config.h>
#include "mb_header.h"
#include "mb_info.h"
@@ -72,7 +73,7 @@ extern struct syslinux_pm_regs regs;
extern struct my_options {
bool solaris;
bool aout;
-} opt;
+} opt, set;
/* map.c */
#define MAP_HIGH 1
@@ -90,8 +91,12 @@ void mboot_make_memmap(void);
void mboot_apm(void);
/* solaris.c */
+bool kernel_is_solaris(const Elf32_Ehdr *);
void mboot_solaris_dhcp_hack(void);
+/* syslinux.c */
+void mboot_syslinux_info(void);
+
/* initvesa.c */
void set_graphics_mode(const struct multiboot_header *mbh,
struct multiboot_info *mbi);
diff --git a/com32/mboot/solaris.c b/com32/mboot/solaris.c
index 3b316606..1b153ddb 100644
--- a/com32/mboot/solaris.c
+++ b/com32/mboot/solaris.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -35,12 +35,21 @@
#include "mboot.h"
#include <syslinux/pxe.h>
+#include <syslinux/config.h>
+
+bool kernel_is_solaris(const Elf32_Ehdr *eh)
+{
+ return eh->e_ident[EI_OSABI] == 6; /* ABI == Solaris */
+}
void mboot_solaris_dhcp_hack(void)
{
void *dhcpdata;
size_t dhcplen;
+ if (syslinux_derivative_info()->c.filesystem != SYSLINUX_FS_PXELINUX)
+ return;
+
if (!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
mbinfo.drives_addr = map_data(dhcpdata, dhcplen, 4, 0);
if (mbinfo.drives_addr) {
diff --git a/com32/mboot/syslinux.c b/com32/mboot/syslinux.c
new file mode 100644
index 00000000..7de3853e
--- /dev/null
+++ b/com32/mboot/syslinux.c
@@ -0,0 +1,45 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux.c
+ *
+ * Syslinux-specific information for the kernel
+ */
+
+#include <syslinux/config.h>
+#include "mboot.h"
+
+void mboot_syslinux_info(void)
+{
+ const struct syslinux_version *sv;
+
+ sv = syslinux_version();
+ mbinfo.boot_loader_name = map_string(sv->version_string);
+ if (mbinfo.boot_loader_name)
+ mbinfo.flags |= MB_INFO_BOOT_LOADER_NAME;
+}
diff --git a/com32/menu/menu.h b/com32/menu/menu.h
index 52b4e4dc..1e596e1d 100644
--- a/com32/menu/menu.h
+++ b/com32/menu/menu.h
@@ -180,6 +180,7 @@ extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* These are global parameters regardless of which menu we're displaying */
extern int shiftkey;
extern int hiddenmenu;
+extern int clearmenu;
extern long long totaltimeout;
void parse_configs(char **argv);
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index cbeb9a18..0c392646 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -616,8 +616,9 @@ static inline int shift_is_held(void)
static void print_timeout_message(int tol, int row, const char *msg)
{
+ static int last_msg_len = 0;
char buf[256];
- int nc = 0, nnc;
+ int nc = 0, nnc, padc;
const char *tp = msg;
char tc;
char *tq = buf;
@@ -686,9 +687,17 @@ static void print_timeout_message(int tol, int row, const char *msg)
}
*tq = '\0';
- /* Let's hope 4 spaces on each side is enough... */
- printf("\033[%d;%dH\2#14 %s ", row,
- HSHIFT + 1 + ((WIDTH - nc - 8) >> 1), buf);
+ if (nc >= last_msg_len) {
+ padc = 0;
+ } else {
+ padc = (last_msg_len - nc + 1) >> 1;
+ }
+
+ printf("\033[%d;%dH\2#14%*s%s%*s", row,
+ HSHIFT + 1 + ((WIDTH - nc) >> 1) - padc,
+ padc, "", buf, padc, "");
+
+ last_msg_len = nc;
}
/* Set the background screen, etc. */
@@ -724,6 +733,9 @@ static const char *do_hidden_menu(void)
}
}
+ /* Clear the message from the screen */
+ print_timeout_message(0, HIDDEN_ROW, "");
+
if (cm->ontimeout)
return cm->ontimeout;
else
@@ -1118,6 +1130,9 @@ int main(int argc, char *argv[])
local_cursor_enable(true);
cmdline = run_menu();
+ if (clearmenu)
+ clear_screen();
+
local_cursor_enable(false);
printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index a248721e..d4c8848c 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -34,6 +34,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* These are global parameters regardless of which menu we're displaying */
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
+int clearmenu = 0;
long long totaltimeout = 0;
/* Keep track of global default */
@@ -690,6 +691,8 @@ static void parse_config_file(FILE * f)
m->menu_background = refdup_word(&p);
} else if ((ep = looking_at(p, "hidden"))) {
hiddenmenu = 1;
+ } else if ((ep = looking_at(p, "clear"))) {
+ clearmenu = 1;
} else if ((ep = is_message_name(p, &msgnr))) {
refstr_put(m->messages[msgnr]);
m->messages[msgnr] = refstrdup(skipspace(ep));
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 35906587..44bc1dfb 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -21,7 +21,8 @@ include ../MCONFIG
MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \
- kbdmap.c32 cmd.c32 vpdtest.c32 gpxecmd.c32 ifcpu.c32
+ kbdmap.c32 cmd.c32 vpdtest.c32 gpxecmd.c32 ifcpu.c32 \
+ cpuid.c32
TESTFILES =
diff --git a/com32/modules/chain.c b/com32/modules/chain.c
index 27220143..ad746ee7 100644
--- a/com32/modules/chain.c
+++ b/com32/modules/chain.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -46,14 +46,22 @@
* when you want more than one ISOLINUX per CD/DVD.
*
* ntldr=<loader>:
- * equivalent to -seg 0x2000 -file <loader>, used with WinNT's loaders
+ * equivalent to seg=0x2000 file=<loader> sethidden,
+ * used with WinNT's loaders
+ *
+ * cmldr=<loader>:
+ * used with Recovery Console of Windows NT/2K/XP.
+ * same as ntldr=<loader> & "cmdcons\0" written to
+ * the system name field in the bootsector
*
* freedos=<loader>:
- * equivalent to -seg 0x60 -file <loader>, used with FreeDOS kernel.sys.
+ * equivalent to seg=0x60 file=<loader> sethidden,
+ * used with FreeDOS kernel.sys.
*
* msdos=<loader>
* pcdos=<loader>
- * equivalent to -seg 0x70 -file <loader>, used with DOS' io.sys.
+ * equivalent to seg=0x70 file=<loader> sethidden,
+ * used with DOS' io.sys.
*
* swap:
* if the disk is not fd0/hd0, install a BIOS stub which swaps
@@ -63,6 +71,10 @@
* change type of primary partitions with IDs 01, 04, 06, 07,
* 0b, 0c, or 0e to 1x, except for the selected partition, which
* is converted the other way.
+ *
+ * sethidden:
+ * update the "hidden sectors" (partition offset) field in a
+ * FAT/NTFS boot sector.
*/
#include <com32.h>
@@ -76,6 +88,7 @@
#include <syslinux/loadfile.h>
#include <syslinux/bootrm.h>
#include <syslinux/config.h>
+#include <syslinux/video.h>
#define SECTOR 512 /* bytes/sector */
@@ -84,10 +97,18 @@ static struct options {
uint16_t keeppxe;
uint16_t seg;
bool isolinux;
+ bool cmldr;
bool swap;
bool hide;
+ bool sethidden;
} opt;
+struct data_area {
+ void *data;
+ addr_t base;
+ addr_t size;
+};
+
static inline void error(const char *msg)
{
fputs(msg, stderr);
@@ -388,10 +409,13 @@ static struct part_entry *find_logical_partition(int whichpart, char *table,
/* Adjust the offset to account for the extended partition itself */
ptab[i].start_lba += self->start_lba;
- /* Sanity check entry: must not extend outside the extended partition.
- This is necessary since some OSes put crap in some entries. */
- if (ptab[i].start_lba + ptab[i].length <= self->start_lba ||
- ptab[i].start_lba >= self->start_lba + self->length)
+ /*
+ * Sanity check entry: must not extend outside the
+ * extended partition. This is necessary since some OSes
+ * put crap in some entries. Note that root is non-NULL here.
+ */
+ if (ptab[i].start_lba + ptab[i].length <= root->start_lba ||
+ ptab[i].start_lba >= root->start_lba + root->length)
continue;
/* OK, it's a data partition. Is it the one we're looking for? */
@@ -437,7 +461,7 @@ static struct part_entry *find_logical_partition(int whichpart, char *table,
return NULL;
}
-static void do_boot(void *boot_sector, size_t boot_size,
+static void do_boot(struct data_area *data, int ndata,
struct syslinux_rm_regs *regs)
{
uint16_t *const bios_fbm = (uint16_t *) 0x413;
@@ -448,7 +472,6 @@ static void do_boot(void *boot_sector, size_t boot_size,
uint8_t driveno = regs->edx.b[0];
uint8_t swapdrive = driveno & 0x80;
int i;
- addr_t loadbase = opt.seg ? (opt.seg << 4) : 0x7c00;
mmap = syslinux_memory_map();
@@ -457,16 +480,19 @@ static void do_boot(void *boot_sector, size_t boot_size,
return;
}
- /* Nothing below 0x7c00, much simpler... */
-
- if (boot_size >= dosmem - loadbase)
+ endimage = 0;
+ for (i = 0; i < ndata; i++) {
+ if (data[i].base + data[i].size > endimage)
+ endimage = data[i].base + data[i].size;
+ }
+ if (endimage > dosmem)
goto too_big;
- endimage = loadbase + boot_size;
-
- if (syslinux_add_movelist
- (&mlist, loadbase, (addr_t) boot_sector, boot_size))
- goto enomem;
+ for (i = 0; i < ndata; i++) {
+ if (syslinux_add_movelist(&mlist, data[i].base,
+ (addr_t)data[i].data, data[i].size))
+ goto enomem;
+ }
if (opt.swap && driveno != swapdrive) {
static const uint8_t swapstub_master[] = {
@@ -548,6 +574,9 @@ static void do_boot(void *boot_sector, size_t boot_size,
/* Tell the shuffler not to muck with this area... */
syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
+ /* Force text mode */
+ syslinux_force_text_mode();
+
fputs("Booting...\n", stdout);
syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, regs);
error("Chainboot failed!\n");
@@ -637,10 +666,30 @@ static uint32_t get_file_lba(const char *filename)
return lba;
}
+static void usage(void)
+{
+ error("Usage: chain.c32 hd<disk#> [<partition>] [options]\n"
+ " chain.c32 fd<disk#> [options]\n"
+ " chain.c32 mbr:<id> [<partition>] [options]\n"
+ " chain.c32 boot [<partition>] [options]\n"
+ "Options: file=<loader> load file, instead of boot sector\n"
+ " isolinux=<loader> load another version of ISOLINUX\n"
+ " ntldr=<loader> load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n"
+ " cmldr=<loader> load Recovery Console of Windows NT/2K/XP\n"
+ " freedos=<loader> load FreeDOS kernel.sys\n"
+ " msdos=<loader> load MS-DOS io.sys\n"
+ " pcdos=<loader> load PC-DOS ibmbio.com\n"
+ " seg=<segment> jump to <seg>:0000 instead of 0000:7C00\n"
+ " swap swap drive numbers, if bootdisk is not fd0/hd0\n"
+ " hide hide primary partitions, except selected partition\n"
+ " sethidden set the FAT/NTFS hidden sectors field\n"
+ );
+}
+
+
int main(int argc, char *argv[])
{
char *mbr, *p;
- void *boot_sector = NULL;
struct part_entry *partinfo;
struct syslinux_rm_regs regs;
char *drivename, *partition;
@@ -649,7 +698,10 @@ int main(int argc, char *argv[])
uint32_t file_lba = 0;
unsigned char *isolinux_bin;
uint32_t *checksum, *chkhead, *chktail;
- size_t boot_size = SECTOR;
+ struct data_area data[3];
+ int ndata = 0;
+ addr_t load_base;
+ static const char cmldr_signature[8] = "cmdcons";
openconsole(&dev_null_r, &dev_stdcon_w);
@@ -675,24 +727,41 @@ int main(int argc, char *argv[])
} else if (!strncmp(argv[i], "ntldr=", 6)) {
opt.seg = 0x2000; /* NTLDR wants this address */
opt.loadfile = argv[i] + 6;
+ opt.sethidden = true;
+ } else if (!strncmp(argv[i], "cmldr=", 6)) {
+ opt.seg = 0x2000; /* CMLDR wants this address */
+ opt.loadfile = argv[i] + 6;
+ opt.cmldr = true;
+ opt.sethidden = true;
} else if (!strncmp(argv[i], "freedos=", 8)) {
opt.seg = 0x60; /* FREEDOS wants this address */
opt.loadfile = argv[i] + 8;
+ opt.sethidden = true;
} else if (!strncmp(argv[i], "msdos=", 6) ||
!strncmp(argv[i], "pcdos=", 6)) {
opt.seg = 0x70; /* MS-DOS 2.0+ wants this address */
opt.loadfile = argv[i] + 6;
+ opt.sethidden = true;
} else if (!strcmp(argv[i], "swap")) {
opt.swap = true;
+ } else if (!strcmp(argv[i], "noswap")) {
+ opt.swap = false;
} else if (!strcmp(argv[i], "hide")) {
opt.hide = true;
+ } else if (!strcmp(argv[i], "nohide")) {
+ opt.hide = false;
} else if (!strcmp(argv[i], "keeppxe")) {
opt.keeppxe = 3;
- } else
- if (((argv[i][0] == 'h' || argv[i][0] == 'f') && argv[i][1] == 'd')
- || !strncmp(argv[i], "mbr:", 4)
- || !strncmp(argv[i], "mbr=", 4)
- || !strcmp(argv[i], "boot") || !strncmp(argv[i], "boot,", 5)) {
+ } else if (!strcmp(argv[i], "sethidden")) {
+ opt.sethidden = true;
+ } else if (!strcmp(argv[i], "nosethidden")) {
+ opt.sethidden = false;
+ } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
+ && argv[i][1] == 'd')
+ || !strncmp(argv[i], "mbr:", 4)
+ || !strncmp(argv[i], "mbr=", 4)
+ || !strcmp(argv[i], "boot")
+ || !strncmp(argv[i], "boot,", 5)) {
drivename = argv[i];
p = strchr(drivename, ',');
if (p) {
@@ -703,20 +772,7 @@ int main(int argc, char *argv[])
partition = argv[++i];
}
} else {
- error
- ("Usage: chain.c32 hd<disk#> [<partition>] [options]\n"
- " chain.c32 fd<disk#> [options]\n"
- " chain.c32 mbr:<id> [<partition>] [options]\n"
- " chain.c32 boot [<partition>] [options]\n"
- "Options: file=<loader> load file, instead of boot sector\n"
- " isolinux=<loader> load another version of ISOLINUX\n"
- " ntldr=<loader> load Windows bootloaders: NTLDR, SETUPLDR, BOOTMGR\n"
- " freedos=<loader> load FreeDOS kernel.sys\n"
- " msdos=<loader> load MS-DOS io.sys\n"
- " pcdos=<loader> load PC-DOS ibmbio.com\n"
- " seg=<segment> jump to <seg>:0000 instead of 0000:7C00\n"
- " swap swap drive numbers, if bootdisk is not fd0/hd0\n"
- " hide hide primary partitions, except selected partition\n");
+ usage();
goto bail;
}
}
@@ -755,7 +811,6 @@ int main(int argc, char *argv[])
regs.ebx.b[0] = regs.edx.b[0] = drive;
whichpart = 0; /* Default */
-
if (partition)
whichpart = strtoul(partition, NULL, 0);
@@ -763,6 +818,14 @@ int main(int argc, char *argv[])
error("Warning: Partitions of floppy devices may not work\n");
}
+ /*
+ * grldr of Grub4dos wants the partition number in DH:
+ * -1: whole drive (default)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+ regs.edx.b[1] = whichpart-1;
+
/* Get the disk geometry and disk access setup */
if (get_disk_params(drive)) {
error("Cannot get disk parameters\n");
@@ -786,7 +849,6 @@ int main(int argc, char *argv[])
/* Boot the MBR */
partinfo = NULL;
- boot_sector = mbr;
} else if (whichpart <= 4) {
/* Boot a primary partition */
@@ -808,12 +870,16 @@ int main(int argc, char *argv[])
}
/* Do the actual chainloading */
+ load_base = opt.seg ? (opt.seg << 4) : 0x7c00;
+
if (opt.loadfile) {
fputs("Loading the boot file...\n", stdout);
- if (loadfile(opt.loadfile, &boot_sector, &boot_size)) {
+ if (loadfile(opt.loadfile, &data[ndata].data, &data[ndata].size)) {
error("Failed to load the boot file\n");
goto bail;
}
+ data[ndata].base = load_base;
+ load_base = 0x7c00; /* If we also load a boot sector */
/* Create boot info table: needed when you want to chainload
another version of ISOLINUX (or another bootlaoder that needs
@@ -840,7 +906,7 @@ int main(int argc, char *argv[])
LBA of primary volume descriptor should already be set to 16.
*/
- isolinux_bin = (unsigned char *)boot_sector;
+ isolinux_bin = (unsigned char *)data[ndata].data;
/* Get LBA address of bootfile */
file_lba = get_file_lba(opt.loadfile);
@@ -850,20 +916,27 @@ int main(int argc, char *argv[])
goto bail;
}
/* Set it */
- *((uint32_t *) & isolinux_bin[12]) = file_lba;
+ *((uint32_t *) &isolinux_bin[12]) = file_lba;
/* Set boot file length */
- *((uint32_t *) & isolinux_bin[16]) = boot_size;
+ *((uint32_t *) &isolinux_bin[16]) = data[ndata].size;
/* Calculate checksum */
- checksum = (uint32_t *) & isolinux_bin[20];
- chkhead = (uint32_t *) & isolinux_bin[64];
- chktail = (uint32_t *) & isolinux_bin[boot_size - 1];
- /* Fresh checksum and clear possibly fractional uint32_t at the end */
- *checksum = *((uint32_t *) & isolinux_bin[boot_size]) = 0;
-
- while (chkhead <= chktail) {
+ checksum = (uint32_t *) &isolinux_bin[20];
+ chkhead = (uint32_t *) &isolinux_bin[64];
+ chktail = (uint32_t *) &isolinux_bin[data[ndata].size & ~3];
+ *checksum = 0;
+ while (chkhead < chktail)
*checksum += *chkhead++;
+
+ /*
+ * Deal with possible fractional dword at the end;
+ * this *should* never happen...
+ */
+ if (data[ndata].size & 3) {
+ uint32_t xword = 0;
+ memcpy(&xword, chkhead, data[ndata].size & 3);
+ *checksum += xword;
}
} else {
error
@@ -872,30 +945,60 @@ int main(int argc, char *argv[])
}
}
- } else if (partinfo) {
+ ndata++;
+ }
+
+ if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) {
/* Actually read the boot sector */
- /* Pick the first buffer that isn't already in use */
- if (!(boot_sector = read_sector(partinfo->start_lba))) {
+ if (!partinfo) {
+ data[ndata].data = mbr;
+ } else if (!(data[ndata].data = read_sector(partinfo->start_lba))) {
error("Cannot read boot sector\n");
goto bail;
}
- }
-
- if (!opt.loadfile) {
- if (*(uint16_t *) ((char *)boot_sector + boot_size - 2) != 0xaa55) {
- error
- ("Boot sector signature not found (unbootable disk/partition?)\n");
+ data[ndata].size = SECTOR;
+ data[ndata].base = load_base;
+
+ if (!opt.loadfile &&
+ *(uint16_t *)((char *)data[ndata].data +
+ data[ndata].size - 2) != 0xaa55) {
+ error("Boot sector signature not found (unbootable disk/partition?)\n");
goto bail;
}
+
+ /*
+ * To boot the Recovery Console of Windows NT/2K/XP we need to write
+ * the string "cmdcons\0" to memory location 0000:7C03.
+ * Memory location 0000:7C00 contains the bootsector of the partition.
+ */
+ if (partinfo && opt.cmldr) {
+ memcpy((char *)data[ndata].data+3, cmldr_signature,
+ sizeof cmldr_signature);
+ }
+
+ /*
+ * Modify the hidden sectors (partition offset) copy in memory;
+ * this modifies the field used by FAT and NTFS filesystems, and
+ * possibly other boot loaders which use the same format.
+ */
+ if (partinfo && opt.sethidden) {
+ *(uint32_t *)((char *)data[ndata].data + 28) =
+ partinfo->start_lba;
+ }
+
+ ndata++;
}
if (partinfo) {
/* 0x7BE is the canonical place for the first partition entry. */
+ data[ndata].data = partinfo;
+ data[ndata].base = 0x7be;
+ data[ndata].size = sizeof *partinfo;
+ ndata++;
regs.esi.w[0] = 0x7be;
- memcpy((char *)0x7be, partinfo, sizeof(*partinfo));
}
- do_boot(boot_sector, boot_size, &regs);
+ do_boot(data, ndata, &regs);
bail:
return 255;
diff --git a/com32/modules/cpuid.c b/com32/modules/cpuid.c
new file mode 100644
index 00000000..62a756e5
--- /dev/null
+++ b/com32/modules/cpuid.c
@@ -0,0 +1,60 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/cpu.h>
+#include <console.h>
+#include <com32.h>
+
+static void dump_reg(const char *name, uint32_t val)
+{
+ int i;
+
+ printf("%-3s : %10d 0x%08x ", name, val, val);
+
+ for (i = 3; i >= 0; i--) {
+ uint8_t c = val >> (i*8);
+ putchar((c >= ' ' && c <= '~') ? c : '.');
+ }
+ putchar('\n');
+}
+
+int main(int argc, char *argv[])
+{
+ uint32_t leaf, counter;
+ uint32_t eax, ebx, ecx, edx;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ if (argc < 2 || argc > 4) {
+ printf("Usage: %s leaf [counter]\n", argv[0]);
+ exit(1);
+ }
+
+ leaf = strtoul(argv[1], NULL, 0);
+ counter = (argv > 2) ? strtoul(argv[2], NULL, 0) : 0;
+
+ if (!cpu_has_eflag(EFLAGS_ID)) {
+ printf("The CPUID instruction is not supported\n");
+ exit(1);
+ }
+
+ cpuid_count(leaf, counter, &eax, &ebx, &ecx, &edx);
+
+ dump_reg("eax", eax);
+ dump_reg("ebx", ebx);
+ dump_reg("ecx", ecx);
+ dump_reg("edx", edx);
+
+ return 0;
+}
diff --git a/com32/rosh/MCONFIG b/com32/rosh/MCONFIG
index 30029d15..25c41396 100644
--- a/com32/rosh/MCONFIG
+++ b/com32/rosh/MCONFIG
@@ -17,11 +17,11 @@
## Include the COM32 common configurables
include ../MCONFIG
-# CFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+# CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
# -fomit-frame-pointer -D__COM32__ \
# -nostdinc -iwithprefix include \
# -I$(com32)/libutil/include -I$(com32)/include
# -g3 -dD
-# LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g3 -D_GNU_SOURCE -dD
+# LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g3 -D_GNU_SOURCE -dD
# -U__GNUC__
diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c
index 9a4edae2..720d8644 100644
--- a/com32/rosh/rosh.c
+++ b/com32/rosh/rosh.c
@@ -37,7 +37,7 @@
#define APP_YEAR "2008"
#define APP_VER "beta-b032"
-void rosh_version()
+void rosh_version(void)
{
printf("%s v %s; (c) %s %s.\n", APP_LONGNAME, APP_VER, APP_YEAR,
APP_AUTHOR);
@@ -224,7 +224,7 @@ void rosh_print_tc(struct termios *tio)
* Switches console over to raw input mode. Allows get_key to get just
* 1 key sequence (without delay or display)
*/
-void rosh_console_raw()
+void rosh_console_raw(void)
{
// struct termios itio, ntio;
// tcgetattr(0, &itio);
@@ -241,7 +241,7 @@ void rosh_console_raw()
/*
* Switches back to standard getline mode.
*/
-void rosh_console_std()
+void rosh_console_std(void)
{
// struct termios itio, ntio;
console_ansi_std();
@@ -252,7 +252,7 @@ void rosh_console_std()
* Attempts to get a single key from the console
* returns key pressed
*/
-int rosh_getkey()
+int rosh_getkey(void)
{
int inc;
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;
+}