diff options
author | Sebastian Schmelzer | 2010-10-25 16:53:54 +0200 |
---|---|---|
committer | Sebastian Schmelzer | 2010-10-25 16:53:54 +0200 |
commit | 3050a9253437f4a4b5ad4bf3b3efdc3c660a5137 (patch) | |
tree | 91ac22153e416aac7ca20916b314b5e2ffa871b1 /contrib/syslinux-4.02/dos | |
download | preboot-master.tar.gz preboot-master.tar.xz preboot-master.zip |
Diffstat (limited to 'contrib/syslinux-4.02/dos')
35 files changed, 2556 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/dos/Makefile b/contrib/syslinux-4.02/dos/Makefile new file mode 100644 index 0000000..2667de8 --- /dev/null +++ b/contrib/syslinux-4.02/dos/Makefile @@ -0,0 +1,78 @@ +## ----------------------------------------------------------------------- +## +## 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 +## + +topdir = .. +include $(topdir)/MCONFIG.embedded + +CFLAGS += -D__MSDOS__ +# CFLAGS += -DDEBUG + +LDFLAGS = -T dosexe.ld +OPTFLAGS = -g +INCLUDES = -include code16.h -nostdinc -iwithprefix include \ + -I. -I.. -I../libfat -I ../libinstaller -I ../libinstaller/getopt + +SRCS = syslinux.c \ + ../libinstaller/fat.c \ + ../libinstaller/syslxmod.c \ + ../libinstaller/syslxopt.c \ + ../libinstaller/setadv.c \ + ../libinstaller/getopt/getopt_long.c \ + ../libinstaller/bootsect_bin.c \ + ../libinstaller/mbr_bin.c \ + $(wildcard ../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 = .:../libfat:../libinstaller:../libinstaller/getopt + +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 ../core/ldlinux.sys + +-include .*.d *.tmp diff --git a/contrib/syslinux-4.02/dos/__divdi3.c b/contrib/syslinux-4.02/dos/__divdi3.c new file mode 100644 index 0000000..97c7795 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/__udivmoddi4.c b/contrib/syslinux-4.02/dos/__udivmoddi4.c new file mode 100644 index 0000000..ca476b7 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/argv.c b/contrib/syslinux-4.02/dos/argv.c new file mode 100644 index 0000000..056aae5 --- /dev/null +++ b/contrib/syslinux-4.02/dos/argv.c @@ -0,0 +1,92 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * argv.c + * + * Parse a single C string into argc and argv (argc is return value.) + * memptr points to available memory. + */ + +#include <inttypes.h> +#include <stddef.h> +#include <stdio.h> + +#define ALIGN_UP(p,t) ((t *)(((uintptr_t)(p) + (sizeof(t)-1)) & ~(sizeof(t)-1))) + +extern char __heap_start[]; +void *__mem_end = &__heap_start; /* Global variable for use by malloc() */ + +int __parse_argv(char ***argv, const char *str) +{ + char *mem = __mem_end; + const char *p = str; + char *q = mem; + char *r; + char **arg; + int wasspace = 0; + int argc = 1; + + /* First copy the string, turning whitespace runs into nulls */ + for (p = str;; p++) { + if (*p <= ' ') { + if (!wasspace) { + wasspace = 1; + *q++ = '\0'; + } + } else { + if (wasspace) { + argc++; + wasspace = 0; + } + *q++ = *p; + } + + /* This test is AFTER we have processed the null byte; + we treat it as a whitespace character so it terminates + the last argument */ + if (!*p) + break; + } + + /* Now create argv */ + arg = ALIGN_UP(q, char *); + *argv = arg; + *arg++ = mem; /* argv[0] */ + + q--; /* Point q to final null */ + for (r = mem; r < q; r++) { + if (*r == '\0') { + *arg++ = r + 1; + } + } + + *arg++ = NULL; /* Null pointer at the end */ + __mem_end = arg; /* End of memory we used */ + + return argc; +} diff --git a/contrib/syslinux-4.02/dos/atou.c b/contrib/syslinux-4.02/dos/atou.c new file mode 100644 index 0000000..e21736d --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/code16.h b/contrib/syslinux-4.02/dos/code16.h new file mode 100644 index 0000000..ca76565 --- /dev/null +++ b/contrib/syslinux-4.02/dos/code16.h @@ -0,0 +1,6 @@ +/* Must be included first of all */ +#ifdef __ASSEMBLY__ + .code16 +#else +__asm__ (".code16gcc"); +#endif diff --git a/contrib/syslinux-4.02/dos/conio.c b/contrib/syslinux-4.02/dos/conio.c new file mode 100644 index 0000000..1400e42 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/crt0.S b/contrib/syslinux-4.02/dos/crt0.S new file mode 100644 index 0000000..3be5712 --- /dev/null +++ b/contrib/syslinux-4.02/dos/crt0.S @@ -0,0 +1,70 @@ + .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 $0xfff8,%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 command line into our own segment + popw %fs # FS -> PSP + movw $_cmdline,%di + movzbw %fs:0x80,%cx + movw $0x81,%si + fs ; rep ; movsb + # Already zero-terminated since we're writing into clean bss + + # Compute argc and argv (assumes REGPARM) + movl $_cmdline,%edx + pushl %eax # Make space for argv + movl %esp,%eax + calll __parse_argv + pushl %eax # argc + + # Initialize malloc + calll __init_memory_arena + + # Now call main... (NOTE: gcc forces main to be regparm 0) + popl %eax # argc + popl %edx # argv + calll main + + # Here %eax is the exit code, fall through into exit + + .size _start,.-_start + + .globl exit + .type exit,@function +exit: + # Exit code already in %eax + movb $0x4c,%ah # Terminate program + int $0x21 +1: hlt + jmp 1b + .size exit,.-exit + + .section ".bss","aw" + .balign 4 +_cmdline: + .space 128 + .size _cmdline,.-_cmdline diff --git a/contrib/syslinux-4.02/dos/ctype.h b/contrib/syslinux-4.02/dos/ctype.h new file mode 100644 index 0000000..c0d00c0 --- /dev/null +++ b/contrib/syslinux-4.02/dos/ctype.h @@ -0,0 +1,3 @@ +static int isspace(int c) { + return (c == ' '); +} diff --git a/contrib/syslinux-4.02/dos/dosexe.ld b/contrib/syslinux-4.02/dos/dosexe.ld new file mode 100644 index 0000000..c67c506 --- /dev/null +++ b/contrib/syslinux-4.02/dos/dosexe.ld @@ -0,0 +1,133 @@ +/* + * 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_ldlinux_size; + .payload : AT (__payload_lma) { + __payload_start = .; + *(.payload) + __payload_end = .; + } + __payload_len = __payload_end - __payload_start; + __payload_dwords = __payload_len >> 2; + + __text_lma = __payload_lma + syslinux_ldlinux_size; + __payload_sseg = (__payload_lma - __text_lma) >> 4; + _exe_text_seg = (__text_lma - __header_size) >> 4; + + __assert1 = ASSERT((__payload_len == syslinux_ldlinux_size), + "syslinux_ldlinux_size must equal the size of .payload"); + + . = 0; + .text : AT (__text_lma) { + *(.text .stub .text.* .gnu.linkonce.t.*) + *(.gnu.warning) + } =0x90909090 + _etext = .; + + . = ALIGN(16); + __rodata_vma = .; + .rodata : AT (__rodata_vma + __text_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 + __text_lma) { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + + _exe_edata_low = ((_edata + __text_lma) & 511); + _exe_edata_blocks = ((_edata + __text_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/contrib/syslinux-4.02/dos/errno.h b/contrib/syslinux-4.02/dos/errno.h new file mode 100644 index 0000000..da733bf --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/free.c b/contrib/syslinux-4.02/dos/free.c new file mode 100644 index 0000000..020dc15 --- /dev/null +++ b/contrib/syslinux-4.02/dos/free.c @@ -0,0 +1,77 @@ +/* + * 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); + +#ifdef DEBUG_MALLOC + assert(ah->a.type == ARENA_TYPE_USED); +#endif + + __free_block(ah); + + /* Here we could insert code to return memory to the system. */ +} diff --git a/contrib/syslinux-4.02/dos/getsetsl.c b/contrib/syslinux-4.02/dos/getsetsl.c new file mode 100644 index 0000000..67e954d --- /dev/null +++ b/contrib/syslinux-4.02/dos/getsetsl.c @@ -0,0 +1,117 @@ +/* + * 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 +#include <inttypes.h> +#include <string.h> +#include <stddef.h> +#include <stdlib.h> + +#include "syslxint.h" + +#define __noinline __attribute__((noinline)) + +#if 0 /* unused */ +uint8_t get_8_sl(const uint8_t * p) +{ + uint8_t v; + + p = set_fs(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(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(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(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(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(p); + asm volatile("movw %1,%%fs:%0":"=m" (*p):"ri"(v)); +} + +void set_32_sl(uint32_t * p, uint32_t v) +{ + p = set_fs(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(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"); +} diff --git a/contrib/syslinux-4.02/dos/header.S b/contrib/syslinux-4.02/dos/header.S new file mode 100644 index 0000000..8367078 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/int2526.S b/contrib/syslinux-4.02/dos/int2526.S new file mode 100644 index 0000000..53e63f8 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/inttypes.h b/contrib/syslinux-4.02/dos/inttypes.h new file mode 100644 index 0000000..9a6118b --- /dev/null +++ b/contrib/syslinux-4.02/dos/inttypes.h @@ -0,0 +1 @@ +#include <stdint.h> diff --git a/contrib/syslinux-4.02/dos/ldlinux.S b/contrib/syslinux-4.02/dos/ldlinux.S new file mode 100644 index 0000000..17a6583 --- /dev/null +++ b/contrib/syslinux-4.02/dos/ldlinux.S @@ -0,0 +1,19 @@ +/* + * Wrap ldlinux.sys; 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 + + .section ".rodata","a" + .balign 4 + .globl syslinux_ldlinux_len +syslinux_ldlinux_len: + .long syslinux_ldlinux_size + .size syslinux_ldlinux_len, .-syslinux_ldlinux_len diff --git a/contrib/syslinux-4.02/dos/malloc.c b/contrib/syslinux-4.02/dos/malloc.c new file mode 100644 index 0000000..55c78c4 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/malloc.h b/contrib/syslinux-4.02/dos/malloc.h new file mode 100644 index 0000000..67bf217 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/memcpy.S b/contrib/syslinux-4.02/dos/memcpy.S new file mode 100644 index 0000000..76eef73 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/memmove.S b/contrib/syslinux-4.02/dos/memmove.S new file mode 100644 index 0000000..1ab2cb2 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/memset.S b/contrib/syslinux-4.02/dos/memset.S new file mode 100644 index 0000000..86e12ab --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/mystuff.h b/contrib/syslinux-4.02/dos/mystuff.h new file mode 100644 index 0000000..2534441 --- /dev/null +++ b/contrib/syslinux-4.02/dos/mystuff.h @@ -0,0 +1,24 @@ +#ifndef MYSTUFF_H +#define MYSTUFF_H + +#include <inttypes.h> + +#define NULL ((void *)0) + +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); + +#endif /* MYSTUFF_H */ diff --git a/contrib/syslinux-4.02/dos/perror.c b/contrib/syslinux-4.02/dos/perror.c new file mode 100644 index 0000000..99ab2f8 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/printf.c b/contrib/syslinux-4.02/dos/printf.c new file mode 100644 index 0000000..4bef266 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/skipatou.c b/contrib/syslinux-4.02/dos/skipatou.c new file mode 100644 index 0000000..655ab56 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/stdint.h b/contrib/syslinux-4.02/dos/stdint.h new file mode 100644 index 0000000..a8391bf --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/stdio.h b/contrib/syslinux-4.02/dos/stdio.h new file mode 100644 index 0000000..c7ca25c --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/stdlib.h b/contrib/syslinux-4.02/dos/stdlib.h new file mode 100644 index 0000000..d346705 --- /dev/null +++ b/contrib/syslinux-4.02/dos/stdlib.h @@ -0,0 +1,16 @@ +#ifndef STDLIB_H +#define STDLIB_H + +typedef int ssize_t; +typedef unsigned int size_t; + +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/contrib/syslinux-4.02/dos/strchr.c b/contrib/syslinux-4.02/dos/strchr.c new file mode 100644 index 0000000..8315311 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/string.h b/contrib/syslinux-4.02/dos/string.h new file mode 100644 index 0000000..f648de2 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/strntoumax.c b/contrib/syslinux-4.02/dos/strntoumax.c new file mode 100644 index 0000000..d8bc73b --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/strtoul.c b/contrib/syslinux-4.02/dos/strtoul.c new file mode 100644 index 0000000..3be9430 --- /dev/null +++ b/contrib/syslinux-4.02/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/contrib/syslinux-4.02/dos/sysexits.h b/contrib/syslinux-4.02/dos/sysexits.h new file mode 100644 index 0000000..483d3ba --- /dev/null +++ b/contrib/syslinux-4.02/dos/sysexits.h @@ -0,0 +1 @@ +#define EX_USAGE 0x40 diff --git a/contrib/syslinux-4.02/dos/syslinux.c b/contrib/syslinux-4.02/dos/syslinux.c new file mode 100644 index 0000000..b5fdfc5 --- /dev/null +++ b/contrib/syslinux-4.02/dos/syslinux.c @@ -0,0 +1,768 @@ +/* ----------------------------------------------------------------------- * + * + * 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" + +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_ldlinux(int fd) +{ + uint16_t ldlinux_seg = ((size_t)syslinux_ldlinux >> 4) + ds(); + uint32_t offset = 0; + uint16_t rv; + uint8_t err; + + while (offset < syslinux_ldlinux_len) { + uint32_t chunk = syslinux_ldlinux_len - offset; + if (chunk > 32768) + chunk = 32768; + 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 & 15), + "SD" ((uint16_t)(ldlinux_seg + (offset >> 4)))); + if (err || rv == 0) + die("file write error"); + offset += rv; + } + + return offset; +} + +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; +} + +static inline __attribute__ ((const)) +uint16_t data_segment(void) +{ + uint16_t ds; + + asm("movw %%ds,%0" : "=rm"(ds)); + return ds; +} + +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 = data_segment(); + + 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 = data_segment(); + + 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 = data_segment(); + + 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 = data_segment(); + + 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) +{ + uint16_t ver; + + asm("int $0x21 ; xchgb %%ah,%%al" + : "=a" (ver) + : "a" (0x3001) + : "ebx", "ecx"); + dos_version = ver; + + 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); +} + +int main(int argc, char *argv[]) +{ + static unsigned char sectbuf[SECTOR_SIZE]; + int dev_fd, fd; + static char ldlinux_name[] = "@:\\ldlinux.sys"; + 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))) { + unlock_device(0); + puts(errmsg); + putchar('\n'); + exit(1); + } + + ldlinux_name[0] = dev_fd | 0x40; + + set_attributes(ldlinux_name, 0); + fd = creat(ldlinux_name, 0); /* SYSTEM HIDDEN READONLY */ + write_ldlinux(fd); + write_file(fd, syslinux_adv, 2 * ADV_SIZE); + close(fd); + set_attributes(ldlinux_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) { + char new_ldlinux_name[160]; + char *cp = new_ldlinux_name + 3; + const char *sd; + int slash = 1; + + new_ldlinux_name[0] = dev_fd | 0x40; + new_ldlinux_name[1] = ':'; + new_ldlinux_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_ldlinux_name + 3) { + if (!slash) + *cp++ = '\\'; + + memcpy(cp, "ldlinux.sys", 12); + + set_attributes(ldlinux_name, 0); + if (rename(ldlinux_name, new_ldlinux_name)) + set_attributes(ldlinux_name, 0x07); + else + set_attributes(new_ldlinux_name, 0x07); + } + } + + /* + * 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); + + /* 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; +} |