aboutsummaryrefslogtreecommitdiff
path: root/dos
diff options
context:
space:
mode:
authorGreg Hartman <ghartman@google.com>2016-11-23 15:51:27 -0800
committerGreg Hartman <ghartman@google.com>2016-11-23 15:52:24 -0800
commit76d05dc695b06c4e987bb8078f78032441e1430c (patch)
tree7b567ae0c1fde3fd699b8839ca39b54aa1c10046 /dos
parent49db3fec5f3681cf8fafd57c8987fcff2d40bc89 (diff)
downloadsyslinux-76d05dc695b06c4e987bb8078f78032441e1430c.tar.gz
Clean checkin of the 6.03 codeandroid-wear-o-preview-4android-wear-o-preview-3android-wear-8.1.0_r1android-vts-8.1_r9android-vts-8.1_r8android-vts-8.1_r7android-vts-8.1_r6android-vts-8.1_r5android-vts-8.1_r4android-vts-8.1_r3android-vts-8.1_r14android-vts-8.1_r13android-vts-8.1_r12android-vts-8.1_r11android-vts-8.1_r10android-vts-8.0_r9android-vts-8.0_r8android-vts-8.0_r7android-vts-8.0_r6android-vts-8.0_r2android-vts-8.0_r13android-vts-8.0_r12android-vts-8.0_r11android-vts-8.0_r10android-vts-8.0_r1android-security-8.1.0_r93android-security-8.1.0_r92android-security-8.1.0_r91android-security-8.1.0_r90android-security-8.1.0_r89android-security-8.1.0_r88android-security-8.1.0_r87android-security-8.1.0_r86android-security-8.1.0_r85android-security-8.1.0_r84android-security-8.1.0_r83android-security-8.1.0_r82android-security-8.0.0_r54android-security-8.0.0_r53android-security-8.0.0_r52android-o-preview-4android-o-preview-3android-o-preview-2android-o-mr1-preview-2android-o-mr1-preview-1android-o-mr1-iot-release-smart-display-r9android-o-mr1-iot-release-smart-display-r8android-o-mr1-iot-release-smart-display-r5android-o-mr1-iot-release-smart-display-r40.1Jandroid-o-mr1-iot-release-smart-display-r4android-o-mr1-iot-release-smart-display-r39android-o-mr1-iot-release-smart-display-r30android-o-mr1-iot-release-smart-display-r3android-o-mr1-iot-release-smart-display-r22android-o-mr1-iot-release-smart-display-r14android-o-mr1-iot-release-smart-clock-r6android-o-mr1-iot-release-smart-clock-r2android-o-mr1-iot-release-smart-clock-fsiandroid-o-mr1-iot-release-smart-clock-fcsandroid-o-mr1-iot-release-cube_r2android-o-mr1-iot-release-cube-fsiandroid-o-mr1-iot-release-cube-fcsandroid-o-mr1-iot-release-1.0.8android-o-mr1-iot-release-1.0.7android-o-mr1-iot-release-1.0.5android-o-mr1-iot-release-1.0.4android-o-mr1-iot-release-1.0.3android-o-mr1-iot-release-1.0.2android-o-mr1-iot-release-1.0.14android-o-mr1-iot-release-1.0.13android-o-mr1-iot-release-1.0.12android-o-mr1-iot-release-1.0.10android-o-mr1-iot-release-1.0.1android-o-mr1-iot-release-1.0.0android-o-mr1-iot-preview-8android-o-mr1-iot-preview-7android-o-mr1-iot-preview-6android-o-iot-preview-5android-cts-8.1_r9android-cts-8.1_r8android-cts-8.1_r7android-cts-8.1_r6android-cts-8.1_r5android-cts-8.1_r4android-cts-8.1_r3android-cts-8.1_r25android-cts-8.1_r24android-cts-8.1_r23android-cts-8.1_r22android-cts-8.1_r21android-cts-8.1_r20android-cts-8.1_r2android-cts-8.1_r19android-cts-8.1_r18android-cts-8.1_r17android-cts-8.1_r16android-cts-8.1_r15android-cts-8.1_r14android-cts-8.1_r13android-cts-8.1_r12android-cts-8.1_r11android-cts-8.1_r10android-cts-8.1_r1android-cts-8.0_r9android-cts-8.0_r8android-cts-8.0_r7android-cts-8.0_r6android-cts-8.0_r5android-cts-8.0_r4android-cts-8.0_r3android-cts-8.0_r26android-cts-8.0_r25android-cts-8.0_r24android-cts-8.0_r23android-cts-8.0_r22android-cts-8.0_r21android-cts-8.0_r20android-cts-8.0_r2android-cts-8.0_r19android-cts-8.0_r18android-cts-8.0_r17android-cts-8.0_r16android-cts-8.0_r15android-cts-8.0_r14android-cts-8.0_r13android-cts-8.0_r12android-cts-8.0_r11android-cts-8.0_r10android-cts-8.0_r1android-8.1.0_r9android-8.1.0_r81android-8.1.0_r80android-8.1.0_r8android-8.1.0_r79android-8.1.0_r78android-8.1.0_r77android-8.1.0_r76android-8.1.0_r75android-8.1.0_r74android-8.1.0_r73android-8.1.0_r72android-8.1.0_r71android-8.1.0_r70android-8.1.0_r7android-8.1.0_r69android-8.1.0_r68android-8.1.0_r67android-8.1.0_r66android-8.1.0_r65android-8.1.0_r64android-8.1.0_r63android-8.1.0_r62android-8.1.0_r61android-8.1.0_r60android-8.1.0_r6android-8.1.0_r53android-8.1.0_r52android-8.1.0_r51android-8.1.0_r50android-8.1.0_r5android-8.1.0_r48android-8.1.0_r47android-8.1.0_r46android-8.1.0_r45android-8.1.0_r43android-8.1.0_r42android-8.1.0_r41android-8.1.0_r40android-8.1.0_r4android-8.1.0_r39android-8.1.0_r38android-8.1.0_r37android-8.1.0_r36android-8.1.0_r35android-8.1.0_r33android-8.1.0_r32android-8.1.0_r31android-8.1.0_r30android-8.1.0_r3android-8.1.0_r29android-8.1.0_r28android-8.1.0_r27android-8.1.0_r26android-8.1.0_r25android-8.1.0_r23android-8.1.0_r22android-8.1.0_r21android-8.1.0_r20android-8.1.0_r2android-8.1.0_r19android-8.1.0_r18android-8.1.0_r17android-8.1.0_r16android-8.1.0_r15android-8.1.0_r14android-8.1.0_r13android-8.1.0_r12android-8.1.0_r11android-8.1.0_r10android-8.1.0_r1android-8.0.0_r9android-8.0.0_r7android-8.0.0_r51android-8.0.0_r50android-8.0.0_r49android-8.0.0_r48android-8.0.0_r47android-8.0.0_r46android-8.0.0_r45android-8.0.0_r44android-8.0.0_r43android-8.0.0_r42android-8.0.0_r41android-8.0.0_r40android-8.0.0_r4android-8.0.0_r39android-8.0.0_r38android-8.0.0_r37android-8.0.0_r36android-8.0.0_r35android-8.0.0_r34android-8.0.0_r33android-8.0.0_r32android-8.0.0_r31android-8.0.0_r30android-8.0.0_r3android-8.0.0_r29android-8.0.0_r28android-8.0.0_r27android-8.0.0_r26android-8.0.0_r25android-8.0.0_r24android-8.0.0_r23android-8.0.0_r22android-8.0.0_r21android-8.0.0_r2android-8.0.0_r17android-8.0.0_r16android-8.0.0_r15android-8.0.0_r13android-8.0.0_r12android-8.0.0_r11android-8.0.0_r10android-8.0.0_r1security-oc-releasesecurity-oc-mr1-releaseoreo-vts-releaseoreo-security-releaseoreo-releaseoreo-r6-releaseoreo-r5-releaseoreo-r4-releaseoreo-r3-releaseoreo-r2-releaseoreo-mr1-wear-releaseoreo-mr1-vts-releaseoreo-mr1-security-releaseoreo-mr1-s1-releaseoreo-mr1-releaseoreo-mr1-iot-releaseoreo-mr1-devoreo-mr1-cuttlefish-testingoreo-mr1-cts-releaseoreo-mr1-1.2-iot-releaseoreo-m8-releaseoreo-m7-releaseoreo-m6-s4-releaseoreo-m6-s3-releaseoreo-m6-s2-releaseoreo-m5-releaseoreo-m4-s9-releaseoreo-m4-s8-releaseoreo-m4-s7-releaseoreo-m4-s6-releaseoreo-m4-s5-releaseoreo-m4-s4-releaseoreo-m4-s3-releaseoreo-m4-s2-releaseoreo-m4-s12-releaseoreo-m4-s11-releaseoreo-m4-s10-releaseoreo-m4-s1-releaseoreo-m3-releaseoreo-m2-s5-releaseoreo-m2-s4-releaseoreo-m2-s3-releaseoreo-m2-s2-releaseoreo-m2-s1-releaseoreo-m2-releaseoreo-dr3-releaseoreo-dr2-releaseoreo-dr1-releaseoreo-dr1-devoreo-devoreo-cts-releaseo-preview-4o-preview-3o-preview-2o-mr1-iot-preview-8o-mr1-iot-preview-7o-mr1-iot-preview-6o-iot-preview-5
BUG: 32495852 Change-Id: I5038a3bb41e217380c1188463daec07b1e9b6b48
Diffstat (limited to 'dos')
-rw-r--r--dos/Makefile79
-rw-r--r--dos/__divdi3.c29
-rw-r--r--dos/__udivmoddi4.c31
-rw-r--r--dos/argv.c126
-rw-r--r--dos/atou.c9
-rw-r--r--dos/code16.h6
-rw-r--r--dos/conio.c42
-rw-r--r--dos/crt0.S91
-rw-r--r--dos/ctype.h3
-rw-r--r--dos/dosexe.ld141
-rw-r--r--dos/errno.h42
-rw-r--r--dos/free.c73
-rw-r--r--dos/getsetsl.c144
-rw-r--r--dos/header.S54
-rw-r--r--dos/int2526.S78
-rw-r--r--dos/inttypes.h1
-rw-r--r--dos/ldlinux.S31
-rw-r--r--dos/malloc.c111
-rw-r--r--dos/malloc.h54
-rw-r--r--dos/memcpy.S23
-rw-r--r--dos/memmove.S36
-rw-r--r--dos/memset.S21
-rw-r--r--dos/mystuff.h79
-rw-r--r--dos/perror.c7
-rw-r--r--dos/printf.c308
-rw-r--r--dos/skipatou.c10
-rw-r--r--dos/stdint.h142
-rw-r--r--dos/stdio.h23
-rw-r--r--dos/stdlib.h23
-rw-r--r--dos/strchr.c17
-rw-r--r--dos/string.h26
-rw-r--r--dos/strntoumax.c73
-rw-r--r--dos/strtoul.c15
-rw-r--r--dos/sysexits.h1
-rw-r--r--dos/syslinux.c769
35 files changed, 2718 insertions, 0 deletions
diff --git a/dos/Makefile b/dos/Makefile
new file mode 100644
index 0000000..b9c337d
--- /dev/null
+++ b/dos/Makefile
@@ -0,0 +1,79 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## MS-DOS FAT installer
+##
+
+include $(MAKEDIR)/embedded.mk
+
+CFLAGS += -D__MSDOS__ -mregparm=3 -DREGPARM=3
+# CFLAGS += -DDEBUG
+
+LDFLAGS = -T $(SRC)/dosexe.ld
+OPTFLAGS = -g
+INCLUDES = -include code16.h -nostdinc -iwithprefix include \
+ -I$(SRC) -I$(SRC)/.. -I$(SRC)/../libfat \
+ -I $(SRC)/../libinstaller -I $(SRC)/../libinstaller/getopt \
+ -I$(objdir)
+
+SRCS = syslinux.c \
+ ../libinstaller/fs.c \
+ ../libinstaller/syslxmod.c \
+ ../libinstaller/syslxopt.c \
+ ../libinstaller/setadv.c \
+ ../libinstaller/getopt/getopt_long.c \
+ ../libinstaller/bootsect_bin.c \
+ ../libinstaller/mbr_bin.c \
+ $(wildcard $(SRC)/../libfat/*.c)
+OBJS = header.o crt0.o ldlinux.o \
+ $(patsubst %.c,%.o,$(notdir $(SRCS)))
+LIBOBJS = int2526.o conio.o memcpy.o memset.o memmove.o skipatou.o atou.o \
+ malloc.o free.o getopt_long.o getsetsl.o strchr.o strtoul.o \
+ strntoumax.o argv.o printf.o __divdi3.o __udivmoddi4.o
+
+VPATH = $(SRC):$(SRC)/../libfat:$(SRC)/../libinstaller:$(SRC)/../libinstaller/getopt:$(OBJ)/../libinstaller
+
+TARGETS = syslinux.com
+
+all: $(TARGETS)
+
+tidy dist:
+ -rm -f *.o *.i *.s *.a .*.d *.tmp *.elf *.lst
+
+clean: tidy
+
+spotless: clean
+ -rm -f *~ $(TARGETS)
+
+installer:
+
+syslinux.elf: $(OBJS) dosexe.ld libcom.a
+ $(LD) $(LDFLAGS) -o $@ $(OBJS) libcom.a
+
+libcom.a: $(LIBOBJS)
+ -rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
+syslinux.com: syslinux.elf
+ $(OBJCOPY) -O binary $< $@
+ $(UPX) --lzma --ultra-brute $@ || \
+ $(UPX) --ultra-brute $@ || \
+ true
+
+%.com: %.asm
+ $(NASM) $(NASMOPT) -f bin -o $@ -MP -MD .$@.d -l $*.lst $<
+
+ldlinux.o: ldlinux.S $(OBJ)/../core/ldlinux.sys
+
+-include .*.d
diff --git a/dos/__divdi3.c b/dos/__divdi3.c
new file mode 100644
index 0000000..97c7795
--- /dev/null
+++ b/dos/__divdi3.c
@@ -0,0 +1,29 @@
+/*
+ * arch/i386/libgcc/__divdi3.c
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+extern uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem);
+
+int64_t __divdi3(int64_t num, int64_t den)
+{
+ int minus = 0;
+ int64_t v;
+
+ if (num < 0) {
+ num = -num;
+ minus = 1;
+ }
+ if (den < 0) {
+ den = -den;
+ minus ^= 1;
+ }
+
+ v = __udivmoddi4(num, den, NULL);
+ if (minus)
+ v = -v;
+
+ return v;
+}
diff --git a/dos/__udivmoddi4.c b/dos/__udivmoddi4.c
new file mode 100644
index 0000000..ca476b7
--- /dev/null
+++ b/dos/__udivmoddi4.c
@@ -0,0 +1,31 @@
+#include <stdint.h>
+
+uint64_t __udivmoddi4(uint64_t num, uint64_t den, uint64_t * rem_p)
+{
+ uint64_t quot = 0, qbit = 1;
+
+ if (den == 0) {
+ asm volatile ("int $0");
+ return 0; /* If trap returns... */
+ }
+
+ /* Left-justify denominator and count shift */
+ while ((int64_t) den >= 0) {
+ den <<= 1;
+ qbit <<= 1;
+ }
+
+ while (qbit) {
+ if (den <= num) {
+ num -= den;
+ quot += qbit;
+ }
+ den >>= 1;
+ qbit >>= 1;
+ }
+
+ if (rem_p)
+ *rem_p = num;
+
+ return quot;
+}
diff --git a/dos/argv.c b/dos/argv.c
new file mode 100644
index 0000000..da28366
--- /dev/null
+++ b/dos/argv.c
@@ -0,0 +1,126 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2013 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * argv.c
+ *
+ * Parse the MS-DOS command line into argc and argv (argc is return value.)
+ * memptr points to available memory.
+ */
+
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include "mystuff.h"
+
+#define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1)))
+
+extern char __heap_start[];
+void *__mem_end = &__heap_start; /* Global variable for use by malloc() */
+
+int __parse_argv(char ***argv)
+{
+ char *mem = __mem_end;
+ const char *str, *p;
+ char *q = mem;
+ char c, *r;
+ char **arg;
+ bool wasspace;
+ int argc;
+ int len;
+ size_t offs;
+ int nulls;
+ uint16_t nstr;
+
+ /* Find and copy argv[0] after the environment block */
+ set_fs(_PSP.environment);
+ offs = 0;
+ nulls = 0;
+ do {
+ if (get_8_fs(offs++) == '\0')
+ nulls++;
+ else
+ nulls = 0;
+ } while (nulls < 2);
+
+ nstr = get_16_fs(offs);
+ offs += 2;
+
+ /* Copy the null-terminated filename string */
+ if (nstr >= 1) {
+ while ((c = get_8_fs(offs++)))
+ *q++ = c;
+ }
+ *q++ = '\0';
+
+ /* Now for the command line tail... */
+
+ len = _PSP.cmdlen;
+ str = _PSP.cmdtail;
+ argc = 1;
+ wasspace = true;
+
+ /* Copy the command tail, turning whitespace runs into nulls */
+ for (p = str;; p++) {
+ if (!len || *p <= ' ') {
+ if (!wasspace) {
+ wasspace = true;
+ *q++ = '\0';
+ }
+ } else {
+ if (wasspace) {
+ argc++;
+ wasspace = false;
+ }
+ *q++ = *p;
+ }
+
+ /* This test is AFTER we have processed the end byte;
+ we treat it as a whitespace character so it terminates
+ the last argument */
+ if (!len--)
+ break;
+ }
+
+ /* Now create argv */
+ arg = ALIGN_UP(q, char *);
+ *argv = arg;
+ *arg++ = mem; /* argv[0] */
+
+ q--; /* Point q to terminal character */
+ for (r = mem; r < q; r++) {
+ if (*r == '\0') {
+ *arg++ = r + 1;
+ }
+ }
+
+ *arg++ = NULL; /* Null pointer at the end */
+ __mem_end = arg; /* End of memory we used */
+
+ return argc;
+}
diff --git a/dos/atou.c b/dos/atou.c
new file mode 100644
index 0000000..e21736d
--- /dev/null
+++ b/dos/atou.c
@@ -0,0 +1,9 @@
+#include "mystuff.h"
+
+unsigned int atou(const char *s)
+{
+ unsigned int i = 0;
+ while (isdigit(*s))
+ i = i * 10 + (*s++ - '0');
+ return i;
+}
diff --git a/dos/code16.h b/dos/code16.h
new file mode 100644
index 0000000..ca76565
--- /dev/null
+++ b/dos/code16.h
@@ -0,0 +1,6 @@
+/* Must be included first of all */
+#ifdef __ASSEMBLY__
+ .code16
+#else
+__asm__ (".code16gcc");
+#endif
diff --git a/dos/conio.c b/dos/conio.c
new file mode 100644
index 0000000..1400e42
--- /dev/null
+++ b/dos/conio.c
@@ -0,0 +1,42 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * conio.c
+ *
+ * Output to the screen
+ */
+
+#include <stdarg.h>
+#include "mystuff.h"
+
+int putchar(int ch)
+{
+ if (ch == '\n')
+ putchar('\r');
+asm("movb $0x02,%%ah ; int $0x21": :"d"(ch));
+ return ch;
+}
+
+/* Note: doesn't put '\n' like the stdc version does */
+int puts(const char *s)
+{
+ int count = 0;
+
+ while (*s) {
+ putchar(*s);
+ count++;
+ s++;
+ }
+
+ return count;
+}
diff --git a/dos/crt0.S b/dos/crt0.S
new file mode 100644
index 0000000..66b52c0
--- /dev/null
+++ b/dos/crt0.S
@@ -0,0 +1,91 @@
+ .code16
+
+#ifndef REGPARM
+# error "This file assumes -mregparm=3 -DREGPARM=3"
+#endif
+
+ .section ".text","ax"
+ .globl _start
+ .type _start,@function
+_start:
+ # Align the stack and make sure the high half is zero
+ andl $0xfffc,%esp
+
+ # DS, ES points to the PSP at this point
+ pushw %es # Save PSP pointer
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+
+ # Clear the .bss
+ cld
+ xorl %eax,%eax
+ movw $__bss_start,%di
+ movw $__bss_end+3,%cx
+ subw %di,%cx
+ shrw $2,%cx
+ rep ; stosl
+
+ # Copy the PSP into our own segment
+ popw %fs # FS -> PSP
+ movw $_PSP,%di
+ xorw %si,%si
+ movw $0x40,%cx
+ fs ; rep ; movsl
+
+ # Verify that this is a supportable DOS version
+ movw $0x3001,%ax
+ int $0x21
+ xchgb %ah,%al
+ movw %ax,dos_version
+ cmpw $0x0314,%ax # DOS >= 3.20?
+ jae 1f # If so, okay
+ movw $bad_dos,%dx # Print error message
+ movb $0x09,%ah
+ int $0x21
+ int $0x20 # Die
+
+1:
+ # Compute argc and argv (assumes REGPARM)
+ pushl %eax # Make space for argv
+ movl %esp,%eax
+ calll __parse_argv
+ pushl %eax # argc
+
+ # Initialize malloc
+ calll __init_memory_arena
+
+ # Now call main
+ popl %eax # argc
+ popl %edx # argv
+ calll main
+
+ # Here %eax is the exit code, fall through into exit
+
+ .size _start,.-_start
+
+ .globl exit
+ .type exit,@function
+exit:
+ # Exit code already in %eax
+ movb $0x4c,%ah # Terminate program
+ int $0x21
+1: hlt
+ jmp 1b
+ .size exit,.-exit
+
+ .section ".rodata","a"
+bad_dos:
+ .ascii "Unsupported DOS version\r\n$"
+ .size bad_dos,.-bad_dos
+
+ .section ".bss","aw"
+ .balign 16
+ .globl _PSP
+_PSP:
+ .space 256
+ .size _PSP, .-_PSP
+
+ /* Purely for sanity */
+ .section ".null","a"
+ .long 0,0,0,0
diff --git a/dos/ctype.h b/dos/ctype.h
new file mode 100644
index 0000000..c0d00c0
--- /dev/null
+++ b/dos/ctype.h
@@ -0,0 +1,3 @@
+static int isspace(int c) {
+ return (c == ' ');
+}
diff --git a/dos/dosexe.ld b/dos/dosexe.ld
new file mode 100644
index 0000000..733f73d
--- /dev/null
+++ b/dos/dosexe.ld
@@ -0,0 +1,141 @@
+/*
+ * Linker script for an MS-DOS EXE binary; this hard-codes a simple
+ * MZ header without relocations.
+ *
+ * For documentation on the MS-DOS MZ EXE format, see:
+ * http://www.delorie.com/djgpp/doc/exe/
+ */
+
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = 0;
+ /* EXE header, from header.S */
+ .header : {
+ *(.header)
+ } =0
+
+ . = ALIGN(16);
+ __header_size = .;
+ __payload_lma = .;
+
+ . = 0x100000000 - syslinux_size;
+ .payload : AT (__payload_lma) {
+ __payload_start = .;
+ *(.payload)
+ __payload_end = .;
+ }
+ __payload_len = ABSOLUTE(__payload_end) - ABSOLUTE(__payload_start);
+ __payload_dwords = __payload_len >> 2;
+
+ __dgroup_lma = __payload_lma + syslinux_size;
+ __payload_sseg = (__payload_lma - __dgroup_lma) >> 4;
+ _exe_text_seg = (__dgroup_lma - __header_size) >> 4;
+
+/*
+ * __assert1 = ASSERT((__payload_len == syslinux_ldlinux_size),
+ * "syslinux_size must equal the size of .payload");
+ */
+ . = 0;
+ __null = .;
+ .null : AT(__dgroup_lma) {
+ *(.null)
+ }
+
+ . = ALIGN(16);
+ __text_vma = .;
+ .text : AT (__text_vma + __dgroup_lma) {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.gnu.warning)
+ } =0x90909090
+ _etext = .;
+
+ . = ALIGN(16);
+ __rodata_vma = .;
+ .rodata : AT (__rodata_vma + __dgroup_lma) {
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ }
+
+ /* Adjust the address for the data segment. Avoid mixing code and
+ data within same 128-byte chunk. */
+ . = ALIGN(128);
+ __data_vma = .;
+ .data : AT (__data_vma + __dgroup_lma) {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .;
+
+ _exe_edata_low = ((_edata + __dgroup_lma) & 511);
+ _exe_edata_blocks = ((_edata + __dgroup_lma) + 511) >> 9;
+
+ .bss (NOLOAD) : {
+ __bss_start = .;
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ __bss_end = .;
+ }
+
+ . = ALIGN(16);
+ .heap (NOLOAD) : {
+ __heap_start = .;
+ *(.heap)
+ __heap_end = .;
+ }
+
+ . = ALIGN(16);
+ .stack (NOLOAD) : {
+ __stack_start = .;
+ *(.stack)
+ __stack_end = .;
+ }
+ . = ALIGN(16);
+ _end = .;
+
+ _exe_bss_paras = (_end - __bss_start) >> 4;
+
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/dos/errno.h b/dos/errno.h
new file mode 100644
index 0000000..da733bf
--- /dev/null
+++ b/dos/errno.h
@@ -0,0 +1,42 @@
+#ifndef ERRNO_H
+#define ERRNO_H
+
+#define EPERM 1 /* Operation not permitted */
+#define ENOENT 2 /* No such file or directory */
+#define ESRCH 3 /* No such process */
+#define EINTR 4 /* Interrupted system call */
+#define EIO 5 /* I/O error */
+#define ENXIO 6 /* No such device or address */
+#define E2BIG 7 /* Argument list too long */
+#define ENOEXEC 8 /* Exec format error */
+#define EBADF 9 /* Bad file number */
+#define ECHILD 10 /* No child processes */
+#define EAGAIN 11 /* Try again */
+#define ENOMEM 12 /* Out of memory */
+#define EACCES 13 /* Permission denied */
+#define EFAULT 14 /* Bad address */
+#define ENOTBLK 15 /* Block device required */
+#define EBUSY 16 /* Device or resource busy */
+#define EEXIST 17 /* File exists */
+#define EXDEV 18 /* Cross-device link */
+#define ENODEV 19 /* No such device */
+#define ENOTDIR 20 /* Not a directory */
+#define EISDIR 21 /* Is a directory */
+#define EINVAL 22 /* Invalid argument */
+#define ENFILE 23 /* File table overflow */
+#define EMFILE 24 /* Too many open files */
+#define ENOTTY 25 /* Not a typewriter */
+#define ETXTBSY 26 /* Text file busy */
+#define EFBIG 27 /* File too large */
+#define ENOSPC 28 /* No space left on device */
+#define ESPIPE 29 /* Illegal seek */
+#define EROFS 30 /* Read-only file system */
+#define EMLINK 31 /* Too many links */
+#define EPIPE 32 /* Broken pipe */
+#define EDOM 33 /* Math argument out of domain of func */
+#define ERANGE 34 /* Math result not representable */
+
+int errno;
+void perror(const char *);
+
+#endif /* ERRNO_H */
diff --git a/dos/free.c b/dos/free.c
new file mode 100644
index 0000000..b0b72ef
--- /dev/null
+++ b/dos/free.c
@@ -0,0 +1,73 @@
+/*
+ * free.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include "malloc.h"
+
+static struct free_arena_header *__free_block(struct free_arena_header *ah)
+{
+ struct free_arena_header *pah, *nah;
+
+ pah = ah->a.prev;
+ nah = ah->a.next;
+ if (pah->a.type == ARENA_TYPE_FREE &&
+ (char *)pah + pah->a.size == (char *)ah) {
+ /* Coalesce into the previous block */
+ pah->a.size += ah->a.size;
+ pah->a.next = nah;
+ nah->a.prev = pah;
+
+#ifdef DEBUG_MALLOC
+ ah->a.type = ARENA_TYPE_DEAD;
+#endif
+
+ ah = pah;
+ pah = ah->a.prev;
+ } else {
+ /* Need to add this block to the free chain */
+ ah->a.type = ARENA_TYPE_FREE;
+
+ ah->next_free = __malloc_head.next_free;
+ ah->prev_free = &__malloc_head;
+ __malloc_head.next_free = ah;
+ ah->next_free->prev_free = ah;
+ }
+
+ /* In either of the previous cases, we might be able to merge
+ with the subsequent block... */
+ if (nah->a.type == ARENA_TYPE_FREE &&
+ (char *)ah + ah->a.size == (char *)nah) {
+ ah->a.size += nah->a.size;
+
+ /* Remove the old block from the chains */
+ nah->next_free->prev_free = nah->prev_free;
+ nah->prev_free->next_free = nah->next_free;
+ ah->a.next = nah->a.next;
+ nah->a.next->a.prev = ah;
+
+#ifdef DEBUG_MALLOC
+ nah->a.type = ARENA_TYPE_DEAD;
+#endif
+ }
+
+ /* Return the block that contains the called block */
+ return ah;
+}
+
+void free(void *ptr)
+{
+ struct free_arena_header *ah;
+
+ if (!ptr)
+ return;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+ __free_block(ah);
+
+ /* Here we could insert code to return memory to the system. */
+}
diff --git a/dos/getsetsl.c b/dos/getsetsl.c
new file mode 100644
index 0000000..c6e6ae7
--- /dev/null
+++ b/dos/getsetsl.c
@@ -0,0 +1,144 @@
+/*
+ * Special handling for the MS-DOS derivative: syslinux_ldlinux
+ * is a "far" object...
+ */
+
+#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
+#define _BSD_SOURCE
+/* glibc 2.20 deprecates _BSD_SOURCE in favour of _DEFAULT_SOURCE */
+#define _DEFAULT_SOURCE 1
+#include <inttypes.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "syslxint.h"
+#include "mystuff.h"
+
+static inline void *set_fs_sl(const void *p)
+{
+ uint16_t seg;
+
+ seg = ds() + ((size_t) p >> 4);
+ set_fs(seg);
+ return (void *)((size_t) p & 0xf);
+}
+
+#if 0 /* unused */
+uint8_t get_8_sl(const uint8_t * p)
+{
+ uint8_t v;
+
+ p = set_fs_sl(p);
+ asm volatile("movb %%fs:%1,%0":"=q" (v):"m"(*p));
+ return v;
+}
+#endif
+
+uint16_t get_16_sl(const uint16_t * p)
+{
+ uint16_t v;
+
+ p = set_fs_sl(p);
+ asm volatile("movw %%fs:%1,%0":"=r" (v):"m"(*p));
+ return v;
+}
+
+uint32_t get_32_sl(const uint32_t * p)
+{
+ uint32_t v;
+
+ p = set_fs_sl(p);
+ asm volatile("movl %%fs:%1,%0":"=r" (v):"m"(*p));
+ return v;
+}
+
+#if 0 /* unused */
+uint64_t get_64_sl(const uint64_t * p)
+{
+ uint32_t v0, v1;
+ const uint32_t *pp = (const uint32_t *)set_fs_sl(p);
+
+ asm volatile("movl %%fs:%1,%0" : "=r" (v0) : "m" (pp[0]));
+ asm volatile("movl %%fs:%1,%0" : "=r" (v1) : "m" (pp[1]));
+ return v0 + ((uint64_t)v1 << 32);
+}
+#endif
+
+#if 0 /* unused */
+void set_8_sl(uint8_t * p, uint8_t v)
+{
+ p = set_fs_sl(p);
+ asm volatile("movb %1,%%fs:%0":"=m" (*p):"qi"(v));
+}
+#endif
+
+void set_16_sl(uint16_t * p, uint16_t v)
+{
+ p = set_fs_sl(p);
+ asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_32_sl(uint32_t * p, uint32_t v)
+{
+ p = set_fs_sl(p);
+ asm volatile("movl %1,%%fs:%0":"=m" (*p):"ri"(v));
+}
+
+void set_64_sl(uint64_t * p, uint64_t v)
+{
+ uint32_t *pp = (uint32_t *)set_fs_sl(p);
+ asm volatile("movl %1,%%fs:%0" : "=m" (pp[0]) : "ri"((uint32_t)v));
+ asm volatile("movl %1,%%fs:%0" : "=m" (pp[1]) : "ri"((uint32_t)(v >> 32)));
+}
+
+void memcpy_to_sl(void *dst, const void *src, size_t len)
+{
+ uint16_t seg;
+ uint16_t off;
+
+ seg = ds() + ((size_t)dst >> 4);
+ off = (size_t)dst & 15;
+
+ asm volatile("pushw %%es ; "
+ "movw %3,%%es ; "
+ "rep ; movsb ; "
+ "popw %%es"
+ : "+D" (off), "+S" (src), "+c" (len)
+ : "r" (seg)
+ : "memory");
+}
+
+void memcpy_from_sl(void *dst, const void *src, size_t len)
+{
+ uint16_t seg;
+ uint16_t off;
+
+ seg = ds() + ((size_t)src >> 4);
+ off = (size_t)src & 15;
+
+ asm volatile("pushw %%ds ; "
+ "movw %3,%%ds ; "
+ "rep ; movsb ; "
+ "popw %%ds"
+ : "+D" (dst), "+S" (off), "+c" (len)
+ : "r" (seg)
+ : "memory");
+}
+
+void memset_sl(void *dst, int c, size_t len)
+{
+ uint16_t seg;
+ uint16_t off;
+
+ seg = ds() + ((size_t)dst >> 4);
+ off = (size_t)dst & 15;
+
+ asm volatile("pushw %%es ; "
+ "movw %3,%%es ; "
+ "rep ; stosb ; "
+ "popw %%es"
+ : "+D" (off), "+c" (len)
+ : "a" (c), "r" (seg)
+ : "memory");
+}
diff --git a/dos/header.S b/dos/header.S
new file mode 100644
index 0000000..8367078
--- /dev/null
+++ b/dos/header.S
@@ -0,0 +1,54 @@
+STACK_SIZE = 8192
+HEAP_SIZE = 16384
+
+ .section ".header","a"
+ .balign 512
+__header_start:
+ .short 0x5a4d
+ .short _exe_edata_low
+ .short _exe_edata_blocks
+ .short 0 /* Relocation count */
+ .short (__header_end - __header_start) >> 4
+ .short _exe_bss_paras
+ .short _exe_bss_paras
+ .short _exe_text_seg /* SP */
+ .short __stack_end
+ .short 0 /* Checksum */
+ .short _start
+ .short _exe_text_seg /* CS */
+ .short __reloc
+ .short 0 /* Overlay number */
+/*
+ * Don't put these fields in unless we actually have an NE or PE image;
+ * some tools might get confused and assume __reloc = 64 automatically
+ * means an NE/PE image or a Windows image of some sort.
+ */
+#if 0
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .short 0 /* Unknown/pad? */
+ .long 0 /* Pointer to Windows PE header */
+#endif
+ .balign 4
+__reloc:
+ .balign 512
+__header_end:
+
+ .section ".heap","aw"
+ .space HEAP_SIZE
+
+ .section ".stack","aw"
+ .space STACK_SIZE
diff --git a/dos/int2526.S b/dos/int2526.S
new file mode 100644
index 0000000..53e63f8
--- /dev/null
+++ b/dos/int2526.S
@@ -0,0 +1,78 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * int 0x25 and 0x26 direct sector access
+ *
+ * Use assembly wrapper functions for these system calls, since unlike
+ * int 0x21 calls they are "dirty" and can destroy unrelated registers.
+ *
+ * NOTE: these all assume the data buffer is in the data segment, i.e.
+ * %ds == %es == dio.bufseg.
+ *
+ * Usage: int int25_read_sector(drive, dio)
+ * Usage: int int26_write_sector(drive, dio)
+ */
+
+ .code16gcc
+ .text
+
+ .globl int25_read_sector
+ .type int25_read_sector, @function
+int25_read_sector:
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ decw %ax /* AL = drive number (0 = A:) */
+ movw %dx, %bx /* BX = dio structure */
+ movw 6(%bx), %dx /* DX = data buffer */
+ movw $-1, %cx
+ int $0x25
+ jc 1f
+ xorw %ax, %ax /* Error code: 0 = no error */
+1:
+ popfw
+ movzwl %ax, %eax
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ retl
+ .size int25_read_sector, .-int25_read_sector
+
+ .globl int26_write_sector
+ .type int26_write_sector, @function
+int26_write_sector:
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+
+ decw %ax /* AL = drive number (0 = A:) */
+ movw %dx, %bx /* BX = dio structure */
+ movw 6(%bx), %dx /* DX = data buffer */
+ movw $-1, %cx
+ int $0x26
+ jc 1f
+ xorw %ax, %ax /* Error code: 0 = no error */
+1:
+ popfw
+ movzwl %ax, %eax
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+ retl
+ .size int26_write_sector, .-int26_write_sector
diff --git a/dos/inttypes.h b/dos/inttypes.h
new file mode 100644
index 0000000..9a6118b
--- /dev/null
+++ b/dos/inttypes.h
@@ -0,0 +1 @@
+#include <stdint.h>
diff --git a/dos/ldlinux.S b/dos/ldlinux.S
new file mode 100644
index 0000000..9145bd7
--- /dev/null
+++ b/dos/ldlinux.S
@@ -0,0 +1,31 @@
+/*
+ * Wrap ldlinux.sys and ldlinux.c32; this needs special handling for DOS.
+ */
+
+ .section ".payload","aw"
+ .balign 16
+ .globl syslinux_ldlinux, syslinux_ldlinux_size
+syslinux_ldlinux:
+ .incbin "../core/ldlinux.sys"
+ .space ((syslinux_ldlinux - .) & 511)
+syslinux_ldlinux_size = . - syslinux_ldlinux
+ .size syslinux_ldlinux, .-syslinux_ldlinux
+ .globl syslinux_ldlinuxc32, syslinux_ldlinuxc32_size
+syslinux_ldlinuxc32:
+ .incbin "../com32/elflink/ldlinux/ldlinux.c32"
+ .space ((syslinux_ldlinuxc32 - .) & 511)
+syslinux_ldlinuxc32_size = . - syslinux_ldlinuxc32
+ .size syslinux_ldlinuxc32, .-syslinux_ldlinuxc32
+ .globl syslinux_size
+syslinux_size = . - syslinux_ldlinux
+
+ .section ".rodata","a"
+ .balign 4
+ .globl syslinux_ldlinux_len
+syslinux_ldlinux_len:
+ .long syslinux_ldlinux_size
+ .size syslinux_ldlinux_len, .-syslinux_ldlinux_len
+ .globl syslinux_ldlinuxc32_len
+syslinux_ldlinuxc32_len:
+ .long syslinux_ldlinuxc32_size
+ .size syslinux_ldlinuxc32_len, .-syslinux_ldlinuxc32_len
diff --git a/dos/malloc.c b/dos/malloc.c
new file mode 100644
index 0000000..55c78c4
--- /dev/null
+++ b/dos/malloc.c
@@ -0,0 +1,111 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "malloc.h"
+
+struct free_arena_header __malloc_head = {
+ {
+ ARENA_TYPE_HEAD,
+ 0,
+ &__malloc_head,
+ &__malloc_head,
+ },
+ &__malloc_head,
+ &__malloc_head
+};
+
+extern void *__mem_end; /* In argv.c */
+
+void __init_memory_arena(void)
+{
+ extern char __heap_end[];
+ struct free_arena_header *fp;
+
+ fp = (struct free_arena_header *)__mem_end;
+ fp->a.type = ARENA_TYPE_FREE;
+ fp->a.size = __heap_end - (char *)__mem_end;
+
+ /* Insert into chains */
+ fp->a.next = fp->a.prev = &__malloc_head;
+ fp->next_free = fp->prev_free = &__malloc_head;
+ __malloc_head.a.next = __malloc_head.a.prev = fp;
+ __malloc_head.next_free = __malloc_head.prev_free = fp;
+}
+
+static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
+{
+ size_t fsize;
+ struct free_arena_header *nfp, *na;
+
+ fsize = fp->a.size;
+
+ /* We need the 2* to account for the larger requirements of a free block */
+ if (fsize >= size + 2 * sizeof(struct arena_header)) {
+ /* Bigger block than required -- split block */
+ nfp = (struct free_arena_header *)((char *)fp + size);
+ na = fp->a.next;
+
+ nfp->a.type = ARENA_TYPE_FREE;
+ nfp->a.size = fsize - size;
+ fp->a.type = ARENA_TYPE_USED;
+ fp->a.size = size;
+
+ /* Insert into all-block chain */
+ nfp->a.prev = fp;
+ nfp->a.next = na;
+ na->a.prev = nfp;
+ fp->a.next = nfp;
+
+ /* Replace current block on free chain */
+ nfp->next_free = fp->next_free;
+ nfp->prev_free = fp->prev_free;
+ fp->next_free->prev_free = nfp;
+ fp->prev_free->next_free = nfp;
+ } else {
+ /* Allocate the whole block */
+ fp->a.type = ARENA_TYPE_USED;
+
+ /* Remove from free chain */
+ fp->next_free->prev_free = fp->prev_free;
+ fp->prev_free->next_free = fp->next_free;
+ }
+
+ return (void *)(&fp->a + 1);
+}
+
+void *malloc(size_t size)
+{
+ struct free_arena_header *fp;
+
+ if (size == 0)
+ return NULL;
+
+ /* Add the obligatory arena header, and round up */
+ size = (size + 2 * sizeof(struct arena_header) - 1) & ~ARENA_SIZE_MASK;
+
+ for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD;
+ fp = fp->next_free) {
+ if (fp->a.size >= size) {
+ /* Found fit -- allocate out of this block */
+ return __malloc_from_block(fp, size);
+ }
+ }
+
+ /* Nothing found... need to request a block from the kernel */
+ return NULL; /* No kernel to get stuff from */
+}
+
+void *calloc(size_t nmemb, size_t size)
+{
+ void *p;
+ size *= nmemb;
+ p = malloc(size);
+ if (p)
+ memset(p, 0, size);
+ return p;
+}
diff --git a/dos/malloc.h b/dos/malloc.h
new file mode 100644
index 0000000..67bf217
--- /dev/null
+++ b/dos/malloc.h
@@ -0,0 +1,54 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+
+/*
+ * This is the minimum chunk size we will ask the kernel for; this should
+ * be a multiple of the page size on all architectures.
+ */
+#define MALLOC_CHUNK_SIZE 65536
+#define MALLOC_CHUNK_MASK (MALLOC_CHUNK_SIZE-1)
+
+/*
+ * This structure should be a power of two. This becomes the
+ * alignment unit.
+ */
+struct free_arena_header;
+
+struct arena_header {
+ size_t type;
+ size_t size; /* Also gives the location of the next entry */
+ struct free_arena_header *next, *prev;
+};
+
+#ifdef DEBUG_MALLOC
+#define ARENA_TYPE_USED 0x64e69c70
+#define ARENA_TYPE_FREE 0x012d610a
+#define ARENA_TYPE_HEAD 0x971676b5
+#define ARENA_TYPE_DEAD 0xeeeeeeee
+#else
+#define ARENA_TYPE_USED 0
+#define ARENA_TYPE_FREE 1
+#define ARENA_TYPE_HEAD 2
+#endif
+
+#define ARENA_SIZE_MASK (sizeof(struct arena_header)-1)
+
+#define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ARENA_SIZE_MASK) & ~ARENA_SIZE_MASK))
+#define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ~ARENA_SIZE_MASK))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+ struct arena_header a;
+ struct free_arena_header *next_free, *prev_free;
+};
+
+extern struct free_arena_header __malloc_head;
diff --git a/dos/memcpy.S b/dos/memcpy.S
new file mode 100644
index 0000000..76eef73
--- /dev/null
+++ b/dos/memcpy.S
@@ -0,0 +1,23 @@
+#
+# memcpy.S
+#
+# Simple 16-bit memcpy() implementation
+#
+
+ .text
+ .code16gcc
+ .globl memcpy
+ .type memcpy, @function
+memcpy:
+ cld
+ pushw %di
+ pushw %si
+ movw %ax,%di
+ movw %dx,%si
+ # The third argument is already in cx
+ rep ; movsb
+ popw %si
+ popw %di
+ ret
+
+ .size memcpy,.-memcpy
diff --git a/dos/memmove.S b/dos/memmove.S
new file mode 100644
index 0000000..1ab2cb2
--- /dev/null
+++ b/dos/memmove.S
@@ -0,0 +1,36 @@
+#
+# memmove.S
+#
+# Simple 16-bit memmove() implementation
+#
+
+ .text
+ .code16gcc
+ .globl memmove
+ .type memmove, @function
+memmove:
+ pushw %di
+ pushw %si
+ movw %ax,%di
+ movw %dx,%si
+ cmpw %si,%di
+ ja 1f
+ # The third argument is already in cx
+ cld
+ rep ; movsb
+2:
+ popw %si
+ popw %di
+ ret
+
+1: /* si <= di, need reverse copy */
+ add %cx,%di
+ add %cx,%si
+ dec %di
+ dec %si
+ std
+ rep ; movsb
+ cld
+ jmp 2b
+
+ .size memmove,.-memmove
diff --git a/dos/memset.S b/dos/memset.S
new file mode 100644
index 0000000..86e12ab
--- /dev/null
+++ b/dos/memset.S
@@ -0,0 +1,21 @@
+#
+# memset.S
+#
+# Minimal 16-bit memset() implementation
+#
+
+ .text
+ .code16gcc
+ .globl memset
+ .type memset, @function
+memset:
+ cld
+ pushw %di
+ movw %ax,%di
+ movb %dl,%al
+ # The third argument is already in %cx
+ rep ; stosb
+ popw %di
+ retl
+
+ .size memset,.-memset
diff --git a/dos/mystuff.h b/dos/mystuff.h
new file mode 100644
index 0000000..2d9574d
--- /dev/null
+++ b/dos/mystuff.h
@@ -0,0 +1,79 @@
+#ifndef MYSTUFF_H
+#define MYSTUFF_H
+
+#include <inttypes.h>
+#include <stddef.h>
+
+unsigned int skip_atou(const char **s);
+unsigned int atou(const char *s);
+
+static inline int isdigit(int ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+struct diskio {
+ uint32_t startsector;
+ uint16_t sectors;
+ uint16_t bufoffs, bufseg;
+} __attribute__ ((packed));
+int int25_read_sector(unsigned char drive, struct diskio *dio);
+int int26_write_sector(unsigned char drive, struct diskio *dio);
+
+struct psp {
+ uint16_t int20;
+ uint16_t nextpara;
+ uint8_t resv1;
+ uint8_t dispatcher[5];
+ uint32_t termvector;
+ uint32_t ctrlcvector;
+ uint32_t criterrvector;
+ uint16_t resv2[11];
+ uint16_t environment;
+ uint16_t resv3[23];
+ uint8_t fcb[2][16];
+ uint32_t resv4;
+ uint8_t cmdlen;
+ char cmdtail[127];
+} __attribute__((packed));
+
+extern struct psp _PSP;
+
+static inline __attribute__((const))
+uint16_t ds(void)
+{
+ uint16_t v;
+ asm("movw %%ds,%0":"=rm"(v));
+ return v;
+}
+
+static inline void set_fs(uint16_t seg)
+{
+ asm volatile("movw %0,%%fs"::"rm" (seg));
+}
+
+static inline uint8_t get_8_fs(size_t offs)
+{
+ uint8_t v;
+ asm volatile("movb %%fs:%1,%0"
+ : "=q" (v) : "m" (*(const uint8_t *)offs));
+ return v;
+}
+
+static inline uint16_t get_16_fs(size_t offs)
+{
+ uint16_t v;
+ asm volatile("movw %%fs:%1,%0"
+ : "=r" (v) : "m" (*(const uint16_t *)offs));
+ return v;
+}
+
+static inline uint32_t get_32_fs(size_t offs)
+{
+ uint32_t v;
+ asm volatile("movl %%fs:%1,%0"
+ : "=r" (v) : "m" (*(const uint32_t *)offs));
+ return v;
+}
+
+#endif /* MYSTUFF_H */
diff --git a/dos/perror.c b/dos/perror.c
new file mode 100644
index 0000000..99ab2f8
--- /dev/null
+++ b/dos/perror.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+#include <errno.h>
+
+void perror(const char *msg)
+{
+ printf("%s: error %s\n", msg, errno);
+}
diff --git a/dos/printf.c b/dos/printf.c
new file mode 100644
index 0000000..4bef266
--- /dev/null
+++ b/dos/printf.c
@@ -0,0 +1,308 @@
+/*
+ * Oh, it's a waste of space, but oh-so-yummy for debugging. It's just
+ * initialization code anyway, so it doesn't take up space when we're
+ * actually running. This version of printf() does not include 64-bit
+ * support. "Live with it."
+ *
+ * Most of this code was shamelessly snarfed from the Linux kernel, then
+ * modified. It's therefore GPL.
+ *
+ * printf() isn't actually needed to build syslinux.com, but during
+ * debugging it's handy.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include "mystuff.h"
+
+static int strnlen(const char *s, int maxlen)
+{
+ const char *es = s;
+ while (*es && maxlen) {
+ es++;
+ maxlen--;
+ }
+
+ return (es - s);
+}
+
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+
+#define do_div(n,base) ({ \
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
+
+static char *number(char *str, long num, int base, int size, int precision,
+ int type)
+{
+ char c, sign, tmp[66];
+ const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
+ int i;
+
+ if (type & LARGE)
+ digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ if (type & LEFT)
+ type &= ~ZEROPAD;
+ if (base < 2 || base > 36)
+ return 0;
+ c = (type & ZEROPAD) ? '0' : ' ';
+ sign = 0;
+ if (type & SIGN) {
+ if (num < 0) {
+ sign = '-';
+ num = -num;
+ size--;
+ } else if (type & PLUS) {
+ sign = '+';
+ size--;
+ } else if (type & SPACE) {
+ sign = ' ';
+ size--;
+ }
+ }
+ if (type & SPECIAL) {
+ if (base == 16)
+ size -= 2;
+ else if (base == 8)
+ size--;
+ }
+ i = 0;
+ if (num == 0)
+ tmp[i++] = '0';
+ else
+ while (num != 0)
+ tmp[i++] = digits[do_div(num, base)];
+ if (i > precision)
+ precision = i;
+ size -= precision;
+ if (!(type & (ZEROPAD + LEFT)))
+ while (size-- > 0)
+ *str++ = ' ';
+ if (sign)
+ *str++ = sign;
+ if (type & SPECIAL) {
+ if (base == 8)
+ *str++ = '0';
+ else if (base == 16) {
+ *str++ = '0';
+ *str++ = digits[33];
+ }
+ }
+ if (!(type & LEFT))
+ while (size-- > 0)
+ *str++ = c;
+ while (i < precision--)
+ *str++ = '0';
+ while (i-- > 0)
+ *str++ = tmp[i];
+ while (size-- > 0)
+ *str++ = ' ';
+ return str;
+}
+
+/* Forward decl. needed for IP address printing stuff... */
+int sprintf(char *buf, const char *fmt, ...);
+
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+ int len;
+ unsigned long num;
+ int i, base;
+ char *str;
+ const char *s;
+
+ int flags; /* flags to number() */
+
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+
+ for (str = buf; *fmt; ++fmt) {
+ if (*fmt != '%') {
+ *str++ = *fmt;
+ continue;
+ }
+
+ /* process flags */
+ flags = 0;
+repeat:
+ ++fmt; /* this also skips first '%' */
+ switch (*fmt) {
+ case '-':
+ flags |= LEFT;
+ goto repeat;
+ case '+':
+ flags |= PLUS;
+ goto repeat;
+ case ' ':
+ flags |= SPACE;
+ goto repeat;
+ case '#':
+ flags |= SPECIAL;
+ goto repeat;
+ case '0':
+ flags |= ZEROPAD;
+ goto repeat;
+ }
+
+ /* get field width */
+ field_width = -1;
+ if (isdigit(*fmt))
+ field_width = skip_atou(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ field_width = va_arg(args, int);
+ if (field_width < 0) {
+ field_width = -field_width;
+ flags |= LEFT;
+ }
+ }
+
+ /* get the precision */
+ precision = -1;
+ if (*fmt == '.') {
+ ++fmt;
+ if (isdigit(*fmt))
+ precision = skip_atou(&fmt);
+ else if (*fmt == '*') {
+ ++fmt;
+ /* it's the next argument */
+ precision = va_arg(args, int);
+ }
+ if (precision < 0)
+ precision = 0;
+ }
+
+ /* get the conversion qualifier */
+ qualifier = -1;
+ if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
+ qualifier = *fmt;
+ ++fmt;
+ }
+
+ /* default base */
+ base = 10;
+
+ switch (*fmt) {
+ case 'c':
+ if (!(flags & LEFT))
+ while (--field_width > 0)
+ *str++ = ' ';
+ *str++ = (unsigned char)va_arg(args, int);
+ while (--field_width > 0)
+ *str++ = ' ';
+ continue;
+
+ case 's':
+ s = va_arg(args, char *);
+ len = strnlen(s, precision);
+
+ if (!(flags & LEFT))
+ while (len < field_width--)
+ *str++ = ' ';
+ for (i = 0; i < len; ++i)
+ *str++ = *s++;
+ while (len < field_width--)
+ *str++ = ' ';
+ continue;
+
+ case 'p':
+ if (field_width == -1) {
+ field_width = 2 * sizeof(void *);
+ flags |= ZEROPAD;
+ }
+ str = number(str,
+ (unsigned long)va_arg(args, void *), 16,
+ field_width, precision, flags);
+ continue;
+
+ case 'n':
+ if (qualifier == 'l') {
+ long *ip = va_arg(args, long *);
+ *ip = (str - buf);
+ } else {
+ int *ip = va_arg(args, int *);
+ *ip = (str - buf);
+ }
+ continue;
+
+ case '%':
+ *str++ = '%';
+ continue;
+
+ /* integer number formats - set up the flags and "break" */
+ case 'o':
+ base = 8;
+ break;
+
+ case 'X':
+ flags |= LARGE;
+ case 'x':
+ base = 16;
+ break;
+
+ case 'd':
+ case 'i':
+ flags |= SIGN;
+ case 'u':
+ break;
+
+ default:
+ *str++ = '%';
+ if (*fmt)
+ *str++ = *fmt;
+ else
+ --fmt;
+ continue;
+ }
+ if (qualifier == 'l')
+ num = va_arg(args, unsigned long);
+ else if (qualifier == 'h') {
+ num = (unsigned short)va_arg(args, int);
+ if (flags & SIGN)
+ num = (short)num;
+ } else if (flags & SIGN)
+ num = va_arg(args, int);
+ else
+ num = va_arg(args, unsigned int);
+ str = number(str, num, base, field_width, precision, flags);
+ }
+ *str = '\0';
+ return str - buf;
+}
+
+int sprintf(char *buf, const char *fmt, ...)
+{
+ va_list args;
+ int i;
+
+ va_start(args, fmt);
+ i = vsprintf(buf, fmt, args);
+ va_end(args);
+ return i;
+}
+
+int printf(const char *fmt, ...)
+{
+ char printf_buf[1024];
+ va_list args;
+ int printed;
+
+ va_start(args, fmt);
+ printed = vsprintf(printf_buf, fmt, args);
+ va_end(args);
+
+ puts(printf_buf);
+
+ return printed;
+}
diff --git a/dos/skipatou.c b/dos/skipatou.c
new file mode 100644
index 0000000..655ab56
--- /dev/null
+++ b/dos/skipatou.c
@@ -0,0 +1,10 @@
+#include "mystuff.h"
+
+unsigned int skip_atou(const char **s)
+{
+ int i = 0;
+
+ while (isdigit(**s))
+ i = i * 10 + *((*s)++) - '0';
+ return i;
+}
diff --git a/dos/stdint.h b/dos/stdint.h
new file mode 100644
index 0000000..a8391bf
--- /dev/null
+++ b/dos/stdint.h
@@ -0,0 +1,142 @@
+/*
+ * stdint.h
+ */
+
+#ifndef _STDINT_H
+#define _STDINT_H
+
+/* Exact types */
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+/* Small types */
+
+typedef signed char int_least8_t;
+typedef signed short int_least16_t;
+typedef signed int int_least32_t;
+typedef signed long long int_least64_t;
+
+typedef unsigned char uint_least8_t;
+typedef unsigned short uint_least16_t;
+typedef unsigned int uint_least32_t;
+typedef unsigned long long uint_least64_t;
+
+/* Fast types */
+
+typedef signed char int_fast8_t;
+typedef signed short int_fast16_t;
+typedef signed int int_fast32_t;
+typedef signed long long int_fast64_t;
+
+typedef unsigned char uint_fast8_t;
+typedef unsigned short uint_fast16_t;
+typedef unsigned int uint_fast32_t;
+typedef unsigned long long uint_fast64_t;
+
+/* Pointer types */
+
+typedef int32_t intptr_t;
+typedef uint32_t uintptr_t;
+
+/* Maximal types */
+
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+/*
+ * To be strictly correct...
+ */
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+
+# define INT8_MIN (-128)
+# define INT16_MIN (-32767-1)
+# define INT32_MIN (-2147483647-1)
+# define INT64_MIN (-9223372036854775807LL-1)
+
+# define INT8_MAX (127)
+# define INT16_MAX (32767)
+# define INT32_MAX (2147483647)
+# define INT64_MAX (9223372036854775807LL)
+
+# define UINT8_MAX (255U)
+# define UINT16_MAX (65535U)
+# define UINT32_MAX (4294967295U)
+# define UINT64_MAX (18446744073709551615ULL)
+
+# define INT_LEAST8_MIN (-128)
+# define INT_LEAST16_MIN (-32767-1)
+# define INT_LEAST32_MIN (-2147483647-1)
+# define INT_LEAST64_MIN (-9223372036854775807LL-1)
+
+# define INT_LEAST8_MAX (127)
+# define INT_LEAST16_MAX (32767)
+# define INT_LEAST32_MAX (2147483647)
+# define INT_LEAST64_MAX (9223372036854775807LL)
+
+# define UINT_LEAST8_MAX (255U)
+# define UINT_LEAST16_MAX (65535U)
+# define UINT_LEAST32_MAX (4294967295U)
+# define UINT_LEAST64_MAX (18446744073709551615ULL)
+
+# define INT_FAST8_MIN (-128)
+# define INT_FAST16_MIN (-32767-1)
+# define INT_FAST32_MIN (-2147483647-1)
+# define INT_FAST64_MIN (-9223372036854775807LL-1)
+
+# define INT_FAST8_MAX (127)
+# define INT_FAST16_MAX (32767)
+# define INT_FAST32_MAX (2147483647)
+# define INT_FAST64_MAX (9223372036854775807LL)
+
+# define UINT_FAST8_MAX (255U)
+# define UINT_FAST16_MAX (65535U)
+# define UINT_FAST32_MAX (4294967295U)
+# define UINT_FAST64_MAX (18446744073709551615ULL)
+
+# define INTPTR_MIN (-2147483647-1)
+# define INTPTR_MAX (2147483647)
+# define UINTPTR_MAX (4294967295U)
+
+# define INTMAX_MIN (-9223372036854775807LL-1)
+# define INTMAX_MAX (9223372036854775807LL)
+# define UINTMAX_MAX (18446744073709551615ULL)
+
+/* ptrdiff_t limit */
+# define PTRDIFF_MIN (-2147483647-1)
+# define PTRDIFF_MAX (2147483647)
+
+/* sig_atomic_t limit */
+# define SIG_ATOMIC_MIN (-2147483647-1)
+# define SIG_ATOMIC_MAX (2147483647)
+
+/* size_t limit */
+# define SIZE_MAX (4294967295U)
+
+#endif /* STDC_LIMIT_MACROS */
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+
+# define INT8_C(n) n
+# define INT16_C(n) n
+# define INT32_C(n) n
+# define INT64_C(n) n ## LL
+
+# define UINT8_C(n) n ## U
+# define UINT16_C(n) n ## U
+# define UINT32_C(n) n ## U
+# define UINT64_C(n) n ## ULL
+
+# define INTMAX_C(n) n ## LL
+# define UINTMAX_C(n) n ## ULL
+
+#endif /* STDC_CONSTANT_MACROS */
+
+#endif /* _STDINT_H */
diff --git a/dos/stdio.h b/dos/stdio.h
new file mode 100644
index 0000000..c7ca25c
--- /dev/null
+++ b/dos/stdio.h
@@ -0,0 +1,23 @@
+#ifndef STDIO_H
+#define STDIO_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+typedef unsigned int off_t;
+
+int putchar(int);
+int puts(const char *);
+int sprintf(char *buf, const char *fmt, ...);
+int vsprintf(char *buf, const char *fmt, va_list args);
+int printf(const char *fmt, ...);
+
+#define stdin 0
+#define stdout 1
+#define stderr 2
+
+#define EOF (-1)
+
+#define fprintf(x, y, ...) printf(y, ## __VA_ARGS__)
+
+#endif /* STDIO_H */
diff --git a/dos/stdlib.h b/dos/stdlib.h
new file mode 100644
index 0000000..d982670
--- /dev/null
+++ b/dos/stdlib.h
@@ -0,0 +1,23 @@
+#ifndef STDLIB_H
+#define STDLIB_H
+
+typedef int ssize_t;
+/* size_t is defined elsewhere */
+#if __SIZEOF_POINTER__ == 4
+typedef unsigned int size_t;
+#elif __SIZEOF_POINTER__ == 8
+typedef unsigned long size_t;
+#else
+#error "unsupported architecture"
+#endif
+
+void __attribute__ ((noreturn)) exit(int);
+
+void *malloc(size_t);
+void *calloc(size_t, size_t);
+void free(void *);
+
+extern unsigned long int strtoul(const char *nptr,
+ char **endptr, int base);
+
+#endif
diff --git a/dos/strchr.c b/dos/strchr.c
new file mode 100644
index 0000000..8315311
--- /dev/null
+++ b/dos/strchr.c
@@ -0,0 +1,17 @@
+/*
+ * strchr.c
+ */
+
+#include <string.h>
+#include "mystuff.h"
+
+char *strchr(const char *s, int c)
+{
+ while (*s != (char)c) {
+ if (!*s)
+ return NULL;
+ s++;
+ }
+
+ return (char *)s;
+}
diff --git a/dos/string.h b/dos/string.h
new file mode 100644
index 0000000..f648de2
--- /dev/null
+++ b/dos/string.h
@@ -0,0 +1,26 @@
+/*
+ * string.h
+ */
+
+#ifndef _STRING_H
+#define _STRING_H
+
+/* Standard routines */
+#define memcpy(a,b,c) __builtin_memcpy(a,b,c)
+#define memmove(a,b,c) __builtin_memmove(a,b,c)
+#define memset(a,b,c) __builtin_memset(a,b,c)
+#define strcpy(a,b) __builtin_strcpy(a,b)
+#define strlen(a) __builtin_strlen(a)
+
+/* This only returns true or false */
+static inline int memcmp(const void *__m1, const void *__m2, unsigned int __n)
+{
+ _Bool rv;
+ asm volatile ("cld ; repe ; cmpsb ; setne %0":"=abd" (rv), "+D"(__m1),
+ "+S"(__m2), "+c"(__n));
+ return rv;
+}
+
+extern char *strchr(const char *s, int c);
+
+#endif /* _STRING_H */
diff --git a/dos/strntoumax.c b/dos/strntoumax.c
new file mode 100644
index 0000000..d8bc73b
--- /dev/null
+++ b/dos/strntoumax.c
@@ -0,0 +1,73 @@
+/*
+ * strntoumax.c
+ *
+ * The strntoumax() function and associated
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ctype.h>
+
+static inline int digitval(int ch)
+{
+ if (ch >= '0' && ch <= '9') {
+ return ch - '0';
+ } else if (ch >= 'A' && ch <= 'Z') {
+ return ch - 'A' + 10;
+ } else if (ch >= 'a' && ch <= 'z') {
+ return ch - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n)
+{
+ int minus = 0;
+ uintmax_t v = 0;
+ int d;
+
+ while (n && isspace((unsigned char)*nptr)) {
+ nptr++;
+ n--;
+ }
+
+ /* Single optional + or - */
+ if (n && *nptr == '-') {
+ minus = 1;
+ nptr++;
+ n--;
+ } else if (n && *nptr == '+') {
+ nptr++;
+ }
+
+ if (base == 0) {
+ if (n >= 2 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ base = 16;
+ } else if (n >= 1 && nptr[0] == '0') {
+ n--;
+ nptr++;
+ base = 8;
+ } else {
+ base = 10;
+ }
+ } else if (base == 16) {
+ if (n >= 2 && nptr[0] == '0' && (nptr[1] == 'x' || nptr[1] == 'X')) {
+ n -= 2;
+ nptr += 2;
+ }
+ }
+
+ while (n && (d = digitval(*nptr)) >= 0 && d < base) {
+ v = v * base + d;
+ n--;
+ nptr++;
+ }
+
+ if (endptr)
+ *endptr = (char *)nptr;
+
+ return minus ? -v : v;
+}
diff --git a/dos/strtoul.c b/dos/strtoul.c
new file mode 100644
index 0000000..3be9430
--- /dev/null
+++ b/dos/strtoul.c
@@ -0,0 +1,15 @@
+/*
+ * strtoul.c
+ *
+ * strtoul() function
+ */
+
+#include <stddef.h>
+#include <inttypes.h>
+
+extern uintmax_t strntoumax(const char *nptr, char **endptr, int base, size_t n);
+
+unsigned long strtoul(const char *nptr, char **endptr, int base)
+{
+ return (unsigned long) strntoumax(nptr, endptr, base, ~(size_t) 0);
+}
diff --git a/dos/sysexits.h b/dos/sysexits.h
new file mode 100644
index 0000000..483d3ba
--- /dev/null
+++ b/dos/sysexits.h
@@ -0,0 +1 @@
+#define EX_USAGE 0x40
diff --git a/dos/syslinux.c b/dos/syslinux.c
new file mode 100644
index 0000000..3c45f34
--- /dev/null
+++ b/dos/syslinux.c
@@ -0,0 +1,769 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * 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
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux.c - Linux installer program for SYSLINUX
+ *
+ * Hacked up for DOS.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "mystuff.h"
+
+#include "syslinux.h"
+#include "libfat.h"
+#include "setadv.h"
+#include "sysexits.h"
+#include "syslxopt.h"
+#include "syslxint.h"
+#include "syslxfs.h"
+
+char *program = "syslinux.com"; /* Name of program */
+uint16_t dos_version;
+
+#ifdef DEBUG
+# define dprintf printf
+void pause(void)
+{
+ uint16_t ax;
+
+ asm volatile("int $0x16" : "=a" (ax) : "a" (0));
+}
+#else
+# define dprintf(...) ((void)0)
+# define pause() ((void)0)
+#endif
+
+void unlock_device(int);
+
+void __attribute__ ((noreturn)) die(const char *msg)
+{
+ unlock_device(0);
+ puts("syslinux: ");
+ puts(msg);
+ putchar('\n');
+ exit(1);
+}
+
+void warning(const char *msg)
+{
+ puts("syslinux: warning: ");
+ puts(msg);
+ putchar('\n');
+}
+
+/*
+ * read/write wrapper functions
+ */
+int creat(const char *filename, int mode)
+{
+ uint16_t rv;
+ uint8_t err;
+
+ dprintf("creat(\"%s\", 0x%x)\n", filename, mode);
+
+ rv = 0x3C00;
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "+a" (rv)
+ : "c" (mode), "d" (filename));
+ if (err) {
+ dprintf("rv = %d\n", rv);
+ die("cannot open ldlinux.sys");
+ }
+
+ return rv;
+}
+
+void close(int fd)
+{
+ uint16_t rv = 0x3E00;
+
+ dprintf("close(%d)\n", fd);
+
+ asm volatile ("int $0x21":"+a" (rv)
+ :"b"(fd));
+
+ /* The only error MS-DOS returns for close is EBADF,
+ and we really don't care... */
+}
+
+int rename(const char *oldname, const char *newname)
+{
+ uint16_t rv = 0x5600; /* Also support 43FFh? */
+ uint8_t err;
+
+ dprintf("rename(\"%s\", \"%s\")\n", oldname, newname);
+
+ asm volatile ("int $0x21 ; setc %0":"=bcdm" (err), "+a"(rv)
+ :"d"(oldname), "D"(newname));
+
+ if (err) {
+ dprintf("rv = %d\n", rv);
+ warning("cannot move ldlinux.sys");
+ return rv;
+ }
+
+ return 0;
+}
+
+ssize_t write_file_sl(int fd, const unsigned char _slimg *buf,
+ const unsigned int len)
+{
+ uint32_t filepos = 0;
+ uint16_t rv;
+ uint8_t err;
+
+ while (filepos < len) {
+ uint16_t seg = ((size_t)buf >> 4) + ds();
+ uint16_t offset = (size_t)buf & 15;
+ uint32_t chunk = len - filepos;
+ if (chunk > 32768 - offset)
+ chunk = 32768 - offset;
+ asm volatile ("pushw %%ds ; "
+ "movw %6,%%ds ; "
+ "int $0x21 ; "
+ "popw %%ds ; " "setc %0":"=bcdm" (err), "=a"(rv)
+ :"a"(0x4000), "b"(fd), "c"(chunk), "d" (offset),
+ "SD" (seg));
+ if (err || rv == 0)
+ die("file write error");
+ filepos += rv;
+ buf += rv;
+ }
+
+ return filepos;
+}
+
+ssize_t write_file(int fd, const void *buf, size_t count)
+{
+ uint16_t rv;
+ ssize_t done = 0;
+ uint8_t err;
+
+ dprintf("write_file(%d,%p,%u)\n", fd, buf, count);
+
+ while (count) {
+ asm volatile ("int $0x21 ; setc %0":"=bcdm" (err), "=a"(rv)
+ :"a"(0x4000), "b"(fd), "c"(count), "d"(buf));
+ if (err || rv == 0)
+ die("file write error");
+
+ done += rv;
+ count -= rv;
+ }
+
+ return done;
+}
+
+void write_device(int drive, const void *buf, size_t nsecs, unsigned int sector)
+{
+ uint16_t errnum = 0x0001;
+ struct diskio dio;
+
+ dprintf("write_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector);
+
+ dio.startsector = sector;
+ dio.sectors = nsecs;
+ dio.bufoffs = (uintptr_t) buf;
+ dio.bufseg = ds();
+
+ if (dos_version >= 0x070a) {
+ /* Try FAT32-aware system call first */
+ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n"
+ "1:"
+ : "=a" (errnum)
+ : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive),
+ "S" (1), "m" (dio)
+ : "memory");
+ dprintf(" rv(7305) = %04x", errnum);
+ }
+
+ /* If not supported, try the legacy system call (int2526.S) */
+ if (errnum == 0x0001)
+ errnum = int26_write_sector(drive, &dio);
+
+ if (errnum) {
+ dprintf("rv = %04x\n", errnum);
+ die("sector write error");
+ }
+}
+
+void read_device(int drive, void *buf, size_t nsecs, unsigned int sector)
+{
+ uint16_t errnum = 0x0001;
+ struct diskio dio;
+
+ dprintf("read_device(%d,%p,%u,%u)\n", drive, buf, nsecs, sector);
+
+ dio.startsector = sector;
+ dio.sectors = nsecs;
+ dio.bufoffs = (uintptr_t) buf;
+ dio.bufseg = ds();
+
+ if (dos_version >= 0x070a) {
+ /* Try FAT32-aware system call first */
+ asm volatile("int $0x21 ; jc 1f ; xorw %0,%0\n"
+ "1:"
+ : "=a" (errnum)
+ : "a" (0x7305), "b" (&dio), "c" (-1), "d" (drive),
+ "S" (0), "m" (dio));
+ dprintf(" rv(7305) = %04x", errnum);
+ }
+
+ /* If not supported, try the legacy system call (int2526.S) */
+ if (errnum == 0x0001)
+ errnum = int25_read_sector(drive, &dio);
+
+ if (errnum) {
+ dprintf("rv = %04x\n", errnum);
+ die("sector read error");
+ }
+}
+
+/* Both traditional DOS and FAT32 DOS return this structure, but
+ FAT32 return a lot more data, so make sure we have plenty of space */
+struct deviceparams {
+ uint8_t specfunc;
+ uint8_t devtype;
+ uint16_t devattr;
+ uint16_t cylinders;
+ uint8_t mediatype;
+ uint16_t bytespersec;
+ uint8_t secperclust;
+ uint16_t ressectors;
+ uint8_t fats;
+ uint16_t rootdirents;
+ uint16_t sectors;
+ uint8_t media;
+ uint16_t fatsecs;
+ uint16_t secpertrack;
+ uint16_t heads;
+ uint32_t hiddensecs;
+ uint32_t hugesectors;
+ uint8_t lotsofpadding[224];
+} __attribute__ ((packed));
+
+uint32_t get_partition_offset(int drive)
+{
+ uint8_t err;
+ uint16_t rv;
+ struct deviceparams dp;
+
+ dp.specfunc = 1; /* Get current information */
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0"
+ :"=abcdm" (err), "+a"(rv), "=m"(dp)
+ :"b" (drive), "c" (0x0860), "d" (&dp));
+
+ if (!err)
+ return dp.hiddensecs;
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0"
+ : "=abcdm" (err), "+a" (rv), "=m" (dp)
+ : "b" (drive), "c" (0x4860), "d" (&dp));
+
+ if (!err)
+ return dp.hiddensecs;
+
+ die("could not find partition start offset");
+}
+
+struct rwblock {
+ uint8_t special;
+ uint16_t head;
+ uint16_t cylinder;
+ uint16_t firstsector;
+ uint16_t sectors;
+ uint16_t bufferoffset;
+ uint16_t bufferseg;
+} __attribute__ ((packed));
+
+static struct rwblock mbr = {
+ .special = 0,
+ .head = 0,
+ .cylinder = 0,
+ .firstsector = 0, /* MS-DOS, unlike the BIOS, zero-base sectors */
+ .sectors = 1,
+ .bufferoffset = 0,
+ .bufferseg = 0
+};
+
+void write_mbr(int drive, const void *buf)
+{
+ uint16_t rv;
+ uint8_t err;
+
+ dprintf("write_mbr(%d,%p)", drive, buf);
+
+ mbr.bufferoffset = (uintptr_t) buf;
+ mbr.bufferseg = ds();
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv)
+ :"c"(0x0841), "d"(&mbr), "b"(drive), "m"(mbr));
+
+ dprintf(" rv(0841) = %04x", rv);
+ if (!err) {
+ dprintf("\n");
+ return;
+ }
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0" : "=bcdm" (err), "+a"(rv)
+ :"c"(0x4841), "d"(&mbr), "b"(drive), "m"(mbr));
+
+ dprintf(" rv(4841) = %04x\n", rv);
+ if (err)
+ die("mbr write error");
+}
+
+void read_mbr(int drive, const void *buf)
+{
+ uint16_t rv;
+ uint8_t err;
+
+ dprintf("read_mbr(%d,%p)", drive, buf);
+
+ mbr.bufferoffset = (uintptr_t) buf;
+ mbr.bufferseg = ds();
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
+ :"c"(0x0861), "d"(&mbr), "b"(drive), "m"(mbr));
+
+ dprintf(" rv(0861) = %04x", rv);
+ if (!err) {
+ dprintf("\n");
+ return;
+ }
+
+ rv = 0x440d;
+ asm volatile ("int $0x21 ; setc %0":"=abcdm" (err), "+a"(rv)
+ :"c"(0x4861), "d"(&mbr), "b"(drive), "m"(mbr));
+
+ dprintf(" rv(4841) = %04x\n", rv);
+ if (err)
+ die("mbr read error");
+
+ dprintf("Bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ ((const uint8_t *)buf)[0],
+ ((const uint8_t *)buf)[1],
+ ((const uint8_t *)buf)[2],
+ ((const uint8_t *)buf)[3],
+ ((const uint8_t *)buf)[4],
+ ((const uint8_t *)buf)[5],
+ ((const uint8_t *)buf)[6],
+ ((const uint8_t *)buf)[7]);
+}
+
+/* This call can legitimately fail, and we don't care, so ignore error return */
+void set_attributes(const char *file, int attributes)
+{
+ uint16_t rv = 0x4301;
+
+ dprintf("set_attributes(\"%s\", 0x%02x)\n", file, attributes);
+
+ asm volatile ("int $0x21":"+a" (rv)
+ :"c"(attributes), "d"(file));
+}
+
+/*
+ * Version of the read_device function suitable for libfat
+ */
+int libfat_xpread(intptr_t pp, void *buf, size_t secsize,
+ libfat_sector_t sector)
+{
+ read_device(pp, buf, 1, sector);
+ return secsize;
+}
+
+static inline void get_dos_version(void)
+{
+ dprintf("DOS version %d.%d\n", (dos_version >> 8), dos_version & 0xff);
+}
+
+/* The locking interface relies on static variables. A massive hack :( */
+static uint8_t lock_level, lock_drive;
+
+static inline void set_lock_device(uint8_t device)
+{
+ lock_level = 0;
+ lock_drive = device;
+}
+
+static int do_lock(uint8_t level)
+{
+ uint16_t level_arg = lock_drive + (level << 8);
+ uint16_t rv;
+ uint8_t err;
+#if 0
+ /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */
+ uint16_t lock_call = (dos_version >= 0x070a) ? 0x484A : 0x084A;
+#else
+ uint16_t lock_call = 0x084A; /* MSDN says this is OK for all filesystems */
+#endif
+
+ dprintf("Trying lock %04x... ", level_arg);
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "=a" (rv)
+ : "a" (0x440d), "b" (level_arg),
+ "c" (lock_call), "d" (0x0001));
+ dprintf("%s %04x\n", err ? "err" : "ok", rv);
+
+ return err ? rv : 0;
+}
+
+void lock_device(int level)
+{
+ static int hard_lock = 0;
+ int err;
+
+ if (dos_version < 0x0700)
+ return; /* Win9x/NT only */
+
+ if (!hard_lock) {
+ /* Assume hierarchial "soft" locking supported */
+
+ while (lock_level < level) {
+ int new_level = lock_level + 1;
+ err = do_lock(new_level);
+ if (err) {
+ if (err == 0x0001) {
+ /* Try hard locking next */
+ hard_lock = 1;
+ }
+ goto soft_fail;
+ }
+
+ lock_level = new_level;
+ }
+ return;
+ }
+
+soft_fail:
+ if (hard_lock) {
+ /* Hard locking, only level 4 supported */
+ /* This is needed for Win9x in DOS mode */
+
+ err = do_lock(4);
+ if (err) {
+ if (err == 0x0001) {
+ /* Assume locking is not needed */
+ return;
+ }
+ goto hard_fail;
+ }
+
+ lock_level = 4;
+ return;
+ }
+
+hard_fail:
+ die("could not lock device");
+}
+
+void unlock_device(int level)
+{
+ uint16_t rv;
+ uint8_t err;
+ uint16_t unlock_call;
+
+ if (dos_version < 0x0700)
+ return; /* Win9x/NT only */
+
+#if 0
+ /* DOS 7.10 = Win95 OSR2 = first version with FAT32 */
+ unlock_call = (dos_version >= 0x070a) ? 0x486A : 0x086A;
+#else
+ unlock_call = 0x086A; /* MSDN says this is OK for all filesystems */
+#endif
+
+ if (lock_level == 4 && level > 0)
+ return; /* Only drop the hard lock at the end */
+
+ while (lock_level > level) {
+ uint8_t new_level = (lock_level == 4) ? 0 : lock_level - 1;
+ uint16_t level_arg = (new_level << 8) + lock_drive;
+ rv = 0x440d;
+ dprintf("Trying unlock %04x... ", new_level);
+ asm volatile ("int $0x21 ; setc %0"
+ : "=bcdm" (err), "+a" (rv)
+ : "b" (level_arg), "c" (unlock_call));
+ dprintf("%s %04x\n", err ? "err" : "ok", rv);
+ lock_level = new_level;
+ }
+}
+
+/*
+ * This function does any desired MBR manipulation; called with the device lock held.
+ */
+struct mbr_entry {
+ uint8_t active; /* Active flag */
+ uint8_t bhead; /* Begin head */
+ uint8_t bsector; /* Begin sector */
+ uint8_t bcylinder; /* Begin cylinder */
+ uint8_t filesystem; /* Filesystem value */
+ uint8_t ehead; /* End head */
+ uint8_t esector; /* End sector */
+ uint8_t ecylinder; /* End cylinder */
+ uint32_t startlba; /* Start sector LBA */
+ uint32_t sectors; /* Length in sectors */
+} __attribute__ ((packed));
+
+static void adjust_mbr(int device, int writembr, int set_active)
+{
+ static unsigned char sectbuf[SECTOR_SIZE];
+ int i;
+
+ if (!writembr && !set_active)
+ return; /* Nothing to do */
+
+ read_mbr(device, sectbuf);
+
+ if (writembr) {
+ memcpy(sectbuf, syslinux_mbr, syslinux_mbr_len);
+ *(uint16_t *) (sectbuf + 510) = 0xaa55;
+ }
+
+ if (set_active) {
+ uint32_t offset = get_partition_offset(device);
+ struct mbr_entry *me = (struct mbr_entry *)(sectbuf + 446);
+ int found = 0;
+
+ dprintf("Searching for partition offset: %08x\n", offset);
+
+ for (i = 0; i < 4; i++) {
+ if (me->startlba == offset) {
+ me->active = 0x80;
+ found++;
+ } else {
+ me->active = 0;
+ }
+ me++;
+ }
+
+ if (found < 1) {
+ die("partition not found (-a is not implemented for logical partitions)");
+ } else if (found > 1) {
+ die("multiple aliased partitions found");
+ }
+ }
+
+ write_mbr(device, sectbuf);
+}
+
+static void move_file(int dev_fd, char *pathname, char *filename)
+{
+ char new_name[160];
+ char *cp = new_name + 3;
+ const char *sd;
+ int slash = 1;
+
+ new_name[0] = dev_fd | 0x40;
+ new_name[1] = ':';
+ new_name[2] = '\\';
+
+ for (sd = opt.directory; *sd; sd++) {
+ char c = *sd;
+
+ if (c == '/' || c == '\\') {
+ if (slash)
+ continue;
+ c = '\\';
+ slash = 1;
+ } else {
+ slash = 0;
+ }
+
+ *cp++ = c;
+ }
+
+ /* Skip if subdirectory == root */
+ if (cp > new_name + 3) {
+ if (!slash)
+ *cp++ = '\\';
+
+ memcpy(cp, filename, 12);
+
+ set_attributes(pathname, 0);
+ if (rename(pathname, new_name))
+ set_attributes(pathname, 0x07);
+ else
+ set_attributes(new_name, 0x07);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ static unsigned char sectbuf[SECTOR_SIZE];
+ int dev_fd, fd;
+ static char ldlinux_name[] = "@:\\ldlinux.sys";
+ static char ldlinuxc32_name[] = "@:\\ldlinux.c32";
+ struct libfat_filesystem *fs;
+ libfat_sector_t s, *secp;
+ libfat_sector_t *sectors;
+ int ldlinux_sectors;
+ int32_t ldlinux_cluster;
+ int nsectors;
+ const char *errmsg;
+ int i;
+ int patch_sectors;
+ unsigned char *dp;
+
+ dprintf("argv = %p\n", argv);
+ for (i = 0; i <= argc; i++)
+ dprintf("argv[%d] = %p = \"%s\"\n", i, argv[i], argv[i]);
+
+ get_dos_version();
+
+ argv[0] = program;
+ parse_options(argc, argv, MODE_SYSLINUX_DOSWIN);
+
+ if (!opt.device)
+ usage(EX_USAGE, MODE_SYSLINUX_DOSWIN);
+ if (opt.sectors || opt.heads || opt.reset_adv || opt.set_once
+ || (opt.update_only > 0) || opt.menu_save || opt.offset) {
+ fprintf(stderr,
+ "At least one specified option not yet implemented"
+ " for this installer.\n");
+ exit(1);
+ }
+
+ /*
+ * Create an ADV in memory... this should be smarter.
+ */
+ syslinux_reset_adv(syslinux_adv);
+
+ /*
+ * Figure out which drive we're talking to
+ */
+ dev_fd = (opt.device[0] & ~0x20) - 0x40;
+ if (dev_fd < 1 || dev_fd > 26 || opt.device[1] != ':' || opt.device[2])
+ usage(EX_USAGE, MODE_SYSLINUX_DOSWIN);
+
+ set_lock_device(dev_fd);
+
+ lock_device(2); /* Make sure we can lock the device */
+ read_device(dev_fd, sectbuf, 1, 0);
+ unlock_device(1);
+
+ /*
+ * Check to see that what we got was indeed an MS-DOS boot sector/superblock
+ */
+ if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
+ unlock_device(0);
+ puts(errmsg);
+ putchar('\n');
+ exit(1);
+ }
+
+ ldlinux_name[0] = dev_fd | 0x40;
+ ldlinuxc32_name[0] = dev_fd | 0x40;
+
+ set_attributes(ldlinux_name, 0);
+ fd = creat(ldlinux_name, 0); /* SYSTEM HIDDEN READONLY */
+ write_file_sl(fd, syslinux_ldlinux, syslinux_ldlinux_len);
+ write_file(fd, syslinux_adv, 2 * ADV_SIZE);
+ close(fd);
+ set_attributes(ldlinux_name, 0x07); /* SYSTEM HIDDEN READONLY */
+
+ set_attributes(ldlinuxc32_name, 0);
+ fd = creat(ldlinuxc32_name, 0); /* SYSTEM HIDDEN READONLY */
+ write_file_sl(fd, syslinux_ldlinuxc32, syslinux_ldlinuxc32_len);
+ close(fd);
+ set_attributes(ldlinuxc32_name, 0x07); /* SYSTEM HIDDEN READONLY */
+
+ /*
+ * Now, use libfat to create a block map. This probably
+ * should be changed to use ioctl(...,FIBMAP,...) since
+ * this is supposed to be a simple, privileged version
+ * of the installer.
+ */
+ ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE
+ + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+ sectors = calloc(ldlinux_sectors, sizeof *sectors);
+ lock_device(2);
+ fs = libfat_open(libfat_xpread, dev_fd);
+ ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
+ secp = sectors;
+ nsectors = 0;
+ s = libfat_clustertosector(fs, ldlinux_cluster);
+ while (s && nsectors < ldlinux_sectors) {
+ *secp++ = s;
+ nsectors++;
+ s = libfat_nextsector(fs, s);
+ }
+ libfat_close(fs);
+
+ /*
+ * If requested, move ldlinux.sys
+ */
+ if (opt.directory) {
+ move_file(dev_fd, ldlinux_name, "ldlinux.sys");
+ move_file(dev_fd, ldlinuxc32_name, "ldlinux.c32");
+ }
+
+ /*
+ * Patch ldlinux.sys and the boot sector
+ */
+ i = syslinux_patch(sectors, nsectors, opt.stupid_mode, opt.raid_mode, opt.directory, NULL);
+ patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
+
+ /*
+ * Overwrite the now-patched ldlinux.sys
+ */
+ /* lock_device(3); -- doesn't seem to be needed */
+ dp = syslinux_ldlinux;
+ for (i = 0; i < patch_sectors; i++) {
+ memcpy_from_sl(sectbuf, dp, SECTOR_SIZE);
+ dp += SECTOR_SIZE;
+ write_device(dev_fd, sectbuf, 1, sectors[i]);
+ }
+
+ /*
+ * Muck with the MBR, if desired, while we hold the lock
+ */
+ adjust_mbr(dev_fd, opt.install_mbr, opt.activate_partition);
+
+ /*
+ * To finish up, write the boot sector
+ */
+
+ /* Read the superblock again since it might have changed while mounted */
+ read_device(dev_fd, sectbuf, 1, 0);
+
+ /* Copy the syslinux code into the boot sector */
+ syslinux_make_bootsect(sectbuf, VFAT);
+
+ /* Write new boot sector */
+ if (opt.bootsecfile) {
+ unlock_device(0);
+ fd = creat(opt.bootsecfile, 0x20); /* ARCHIVE */
+ write_file(fd, sectbuf, SECTOR_SIZE);
+ close(fd);
+ } else {
+ write_device(dev_fd, sectbuf, 1, 0);
+ unlock_device(0);
+ }
+
+ /* Done! */
+
+ return 0;
+}