(2006-08-06) rescue-bootcd

This commit is contained in:
2006-08-06 00:00:00 +02:00
parent 2f796b816a
commit decb062d20
21091 changed files with 7076462 additions and 0 deletions

View File

@@ -0,0 +1,27 @@
conio.s: conio.c ../com32/include/stdint.h memdisk.h \
../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \
../com32/include/stddef.h ../com32/include/bitsize/stddef.h \
../com32/include/stdarg.h
e820func.s: e820func.c ../com32/include/stdint.h memdisk.h \
../com32/include/com32.h ../com32/include/klibc/compiler.h e820.h
e820test.s: e820test.c ../com32/include/string.h \
../com32/include/klibc/extern.h ../com32/include/stddef.h \
../com32/include/bitsize/stddef.h ../com32/include/stdio.h \
../com32/include/stdarg.h ../com32/include/stdlib.h \
../com32/include/klibc/compiler.h ../com32/include/inttypes.h \
../com32/include/stdint.h e820.h
inflate.s: inflate.c
msetup.s: msetup.c ../com32/include/stdint.h memdisk.h \
../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \
../com32/include/stddef.h ../com32/include/bitsize/stddef.h \
../com32/include/stdarg.h e820.h
setup.s: setup.c ../com32/include/stdint.h e820.h conio.h \
../com32/include/stddef.h ../com32/include/bitsize/stddef.h \
../com32/include/stdarg.h version.h memdisk.h ../com32/include/com32.h \
../com32/include/klibc/compiler.h
unzip.s: unzip.c ../com32/include/stdint.h memdisk.h \
../com32/include/com32.h ../com32/include/klibc/compiler.h conio.h \
../com32/include/stddef.h ../com32/include/bitsize/stddef.h \
../com32/include/stdarg.h inflate.c
memdisk.bin: memdisk.asm
memdisk16.bin: memdisk16.asm

View File

@@ -0,0 +1,121 @@
#ident "$Id: Makefile,v 1.29 2004/12/29 01:58:02 hpa Exp $"
## -----------------------------------------------------------------------
##
## Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
##
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
## Boston MA 02111-1307, USA; either version 2 of the License, or
## (at your option) any later version; incorporated herein by reference.
##
## -----------------------------------------------------------------------
VERSION := $(shell cat ../version)
gcc_ok = $(shell if gcc $(1) -c -x c /dev/null -o /dev/null 2>/dev/null; \
then echo $(1); else echo $(2); fi)
M32 := $(call gcc_ok,-m32,)
ALIGN := $(call gcc_ok,-falign-functions=0 -falign-jumps=0 -falign-loops=0,-malign-functions=0 -malign-jumps=0 -malign-loops=0)
CC = gcc $(M32)
CFLAGS = -g -W -Wall -Wno-sign-compare \
-Os -fomit-frame-pointer -march=i386 $(ALIGN) \
-DVERSION='"$(VERSION)"' -DDATE='"$(DATE)"'
LDFLAGS = -g
INCLUDE = -I../com32/include
LD = ld -m elf_i386
NASM = nasm -O99
NFLAGS = -dVERSION='"$(VERSION)"' -dDATE='"$(DATE)"'
NINCLUDE =
OBJCOPY = objcopy
PERL = perl
# Important: init.o16 must be first!!
OBJS16 = init.o16 init32.o
OBJS32 = start32.o setup.o msetup.o e820func.o conio.o memcpy.o memset.o \
unzip.o memdisk.o
CSRC = setup.c msetup.c e820func.c conio.c unzip.c
SSRC =
NASMSRC = memdisk.asm memdisk16.asm
all: memdisk e820test
# tidy, clean removes everything except the final binary
tidy:
rm -f *.o *.s *.o16 *.s16 *.bin *.lst *.elf e820test
clean: tidy
# spotless also removes the product binary
spotless: clean
rm -f memdisk .depend
%.o: %.asm
$(NASM) $(NFLAGS) -f elf -l $*.lst -o $@ $<
%.o: %.s
$(CC) -x assembler -c -o $@ $<
%.o16: %.s16
$(CC) -x assembler -c -o $@ $<
%.o: %.c
$(CC) $(INCLUDE) $(CFLAGS) -c -o $@ $<
%.s16: %.s
echo '.code16gcc' | cat - $< > $@
%.s: %.S
$(CC) -x c $(INCLUDE) $(CFLAGS) -traditional -E -o $@ $<
%.s16: %.S16
$(CC) -x c $(INCLUDE) $(CFLAGS) -traditional -E -o $@ $<
%.s: %.c
$(CC) $(INCLUDE) $(CFLAGS) -S -o $@ $<
%.i: %.c
$(CC) $(INCLUDE) $(CFLAGS) -E -o $@ $<
# Cancel default rule
%.o: %.c
%.bin: %.asm
$(NASM) -f bin $(NFLAGS) $(NINCLUDE) -o $@ -l $*.lst $<
memdisk16.elf: $(OBJS16)
$(LD) -Ttext 0 -o $@ $^
memdisk32.elf: $(OBJS32)
$(LD) -Ttext 0x100000 -o $@ $^
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
memdisk: memdisk16.bin memdisk32.bin postprocess.pl
$(PERL) postprocess.pl $@ memdisk16.bin memdisk32.bin
e820test: e820func.o msetup.o e820test.o memdisk.o
$(CC) $(LDFLAGS) -o $@ $^
memdisk.o: memdisk.bin
$(LD) -r -b binary -o $@ $<
.depend:
rm -f .depend
for csrc in *.c ; do $(CC) $(INCLUDE) -MM $$csrc | sed -e 's/\.o/\.s/' >> .depend ; done
for ssrc in $(SSRC) ; do $(CC) $(INCLUDE) -x c -traditional -MM $$ssrc | sed -e 's/\.S16\.o/\.o16/' >> .depend ; done
for nsrc in $(NASMSRC) ; do $(NASM) -DDEPEND $(NINCLUDE) -o `echo $$nsrc | sed -e 's/\.asm/\.bin/'` -M $$nsrc >> .depend ; done
depend:
rm -f .depend
$(MAKE) .depend
# This file contains the version number, so add a dependency for it
setup.s: ../version
# Include dependencies file
include .depend

View File

@@ -0,0 +1,365 @@
#ident "$Id: conio.c,v 1.8 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 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 <stdint.h>
#include "memdisk.h"
#include "conio.h"
int putchar(int ch)
{
com32sys_t regs;
if ( ch == '\n' ) {
/* \n -> \r\n */
putchar('\r');
}
regs.eax.w[0] = 0x0e00|(ch&0xff);
syscall(0x10, &regs, NULL);
return ch;
}
int puts(const char *s)
{
int count = 0;
while ( *s ) {
putchar(*s);
count++;
s++;
}
return count;
}
/*
* 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.
*/
static inline int
isdigit(int ch)
{
return (ch >= '0') && (ch <= '9');
}
static int skip_atoi(const char **s)
{
int i=0;
while (isdigit(**s))
i = i*10 + *((*s)++) - '0';
return i;
}
unsigned int atou(const char *s)
{
unsigned int i = 0;
while (isdigit(*s))
i = i*10 + (*s++ - '0');
return i;
}
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_atoi(&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_atoi(&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;
}

View File

@@ -0,0 +1,32 @@
#ident "$Id: conio.h,v 1.5 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 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.h
*
* Limited console I/O
*/
#ifndef CONIO_H
#define CONIO_H
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
int putchar(int);
int puts(const char *);
int printf(const char *, ...);
unsigned int atou(const char *);
#endif

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
#ident "$Id: e820.h,v 1.4 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 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.
*
* ----------------------------------------------------------------------- */
/*
* e820.h
*
* Common routines for e820 memory map management
*/
#include <stdint.h>
struct e820range {
uint64_t start;
uint32_t type;
} __attribute__((packed));
extern struct e820range ranges[];
extern int nranges;
extern uint32_t dos_mem, low_mem, high_mem;
extern void e820map_init(void);
extern void insertrange(uint64_t, uint64_t, uint32_t);
extern void get_mem(void);
extern void parse_mem(void);

View File

@@ -0,0 +1,13 @@
0000000000000000 000000000009bc00 1
000000000009bc00 0000000000004400 2
00000000000e9800 0000000000016800 2
0000000000100000 0000000006ee0000 1
0000000006fe0000 000000000000fc00 3
0000000006fefc00 0000000000000400 4
0000000006ff0000 0000000000002000 2
0000000006ff2000 000000000000e000 1
0000000007000000 0000000000100000 2
00000000fff00000 0000000000100000 2
0000000000586000 0000000000168000 2
000000000009ba00 0000000000000200 2

View File

@@ -0,0 +1,105 @@
#ident "$Id: e820func.c,v 1.7 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001 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.
*
* ----------------------------------------------------------------------- */
/*
* e820func.c
*
* E820 range database manager
*/
#include <stdint.h>
#include "memdisk.h" /* For memset() */
#include "e820.h"
#define MAXRANGES 64
/* All of memory starts out as one range of "indeterminate" type */
struct e820range ranges[MAXRANGES];
int nranges;
void e820map_init(void)
{
memset(ranges, 0, sizeof(ranges));
nranges = 1;
ranges[1].type = -1;
}
static void insertrange_at(int where, uint64_t start, uint32_t type)
{
int i;
for ( i = nranges ; i > where ; i-- )
ranges[i] = ranges[i-1];
ranges[where].start = start;
ranges[where].type = type;
nranges++;
ranges[nranges].start = 0ULL;
ranges[nranges].type = (uint32_t)-1;
}
void insertrange(uint64_t start, uint64_t len, uint32_t type)
{
uint64_t last;
uint32_t oldtype;
int i, j;
/* Remove this to make len == 0 mean all of memory */
if ( len == 0 )
return; /* Nothing to insert */
last = start+len-1; /* May roll over */
i = 0;
oldtype = -2;
while ( start > ranges[i].start && ranges[i].type != -1 ) {
oldtype = ranges[i].type;
i++;
}
/* Consider the replacement policy. This current one is "overwrite." */
if ( start < ranges[i].start || ranges[i].type == -1 )
insertrange_at(i++, start, type);
while ( i == 0 || last > ranges[i].start-1 ) {
oldtype = ranges[i].type;
ranges[i].type = type;
i++;
}
if ( last < ranges[i].start-1 )
insertrange_at(i, last+1, oldtype);
/* Now the map is correct, but quite possibly not optimal. Scan the
map for ranges which are redundant and remove them. */
i = j = 1;
oldtype = ranges[0].type;
while ( i < nranges ) {
if ( ranges[i].type == oldtype ) {
i++;
} else {
oldtype = ranges[i].type;
if ( i != j )
ranges[j] = ranges[i];
i++; j++;
}
}
if ( i != j ) {
ranges[j] = ranges[i]; /* Termination sentinel copy */
nranges -= (i-j);
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,89 @@
#ident "$Id: e820test.c,v 1.8 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2003 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.
*
* ----------------------------------------------------------------------- */
/*
* e820hack.c
*
* Test of INT 15:E820 canonicalization/manipulation routine
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "e820.h"
void *sys_bounce; /* Dummy */
extern void parse_mem(void);
extern uint32_t dos_mem, low_mem, high_mem;
void __attribute__((noreturn)) die(void)
{
abort();
}
void printranges(void) {
int i;
for ( i = 0 ; i < nranges ; i++ ) {
printf("%016llx %016llx %d\n",
ranges[i].start,
ranges[i+1].start - ranges[i].start,
ranges[i].type);
}
}
int main(void)
{
uint64_t start, len;
uint32_t type;
char line[BUFSIZ], *p;
e820map_init();
printranges();
while ( fgets(line, BUFSIZ, stdin) ) {
p = strchr(line, ':');
p = p ? p+1 : line;
if ( sscanf(p, " %llx %llx %d", &start, &len, &type) == 3 ) {
putchar('\n');
printf("%016llx %016llx %d <-\n", start, len, type);
putchar('\n');
insertrange(start, len, type);
printranges();
}
}
parse_mem();
putchar('\n');
printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
putchar('\n');
/* Now, steal a chunk (2K) of DOS memory and make sure it registered OK */
insertrange(dos_mem-2048, 2048, 2); /* Type 2 = reserved */
printranges();
parse_mem();
putchar('\n');
printf("DOS mem = %#10x (%u K)\n", dos_mem, dos_mem >> 10);
printf("Low mem = %#10x (%u K)\n", low_mem, low_mem >> 10);
printf("High mem = %#10x (%u K)\n", high_mem, high_mem >> 10);
putchar('\n');
return 0;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
# $Id: memcpy.S,v 1.1 2003/04/15 19:31:04 hpa Exp $
#
# memcpy.S
#
# Simple memcpy() implementation
#
.text
.globl memcpy
.type memcpy, @function
memcpy:
cld
pushl %edi
pushl %esi
movl 12(%esp),%edi
movl 16(%esp),%esi
movl 20(%esp),%eax
movl %eax,%ecx
shrl $2,%ecx
rep ; movsl
movl %eax,%ecx
andl $3,%ecx
rep ; movsb
movl 12(%esp),%eax
popl %esi
popl %edi
ret
.size memcpy,.-memcpy

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,759 @@
; -*- fundamental -*- (asm-mode sucks)
; $Id: memdisk.asm,v 1.29 2005/04/29 06:08:03 hpa Exp $
; ****************************************************************************
;
; memdisk.asm
;
; A program to emulate an INT 13h disk BIOS from a "disk" in extended
; memory.
;
; Copyright (C) 2001-2004 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.
;
; ****************************************************************************
%ifndef DEPEND
%include "../version.gen"
%endif
; %define DEBUG_TRACERS ; Uncomment to get debugging tracers
%ifdef DEBUG_TRACERS
%macro TRACER 1
call debug_tracer
db %1
%endmacro
%else ; DEBUG_TRACERS
%macro TRACER 1
%endmacro
%endif ; DEBUG_TRACERS
%define CONFIG_READONLY 0x01
%define CONFIG_RAW 0x02
%define CONFIG_BIGRAW 0x08 ; MUST be 8!
org 0h
%define SECTORSIZE_LG2 9 ; log2(sector size)
%define SECTORSIZE (1 << SECTORSIZE_LG2)
; Parameter registers definition; this is the definition
; of the stack frame.
%define P_DS word [bp+34]
%define P_ES word [bp+32]
%define P_EAX dword [bp+28]
%define P_HAX word [bp+30]
%define P_AX word [bp+28]
%define P_AL byte [bp+28]
%define P_AH byte [bp+29]
%define P_ECX dword [bp+24]
%define P_HCX word [bp+26]
%define P_CX word [bp+24]
%define P_CL byte [bp+24]
%define P_CH byte [bp+25]
%define P_EDX dword [bp+20]
%define P_HDX word [bp+22]
%define P_DX word [bp+20]
%define P_DL byte [bp+20]
%define P_DH byte [bp+21]
%define P_EBX dword [bp+16]
%define P_HBX word [bp+18]
%define P_HBXL byte [bp+18]
%define P_BX word [bp+16]
%define P_BL byte [bp+16]
%define P_BH byte [bp+17]
%define P_EBP dword [bp+8]
%define P_BP word [bp+8]
%define P_ESI dword [bp+4]
%define P_SI word [bp+4]
%define P_EDI dword [bp]
%define P_DI word [bp]
section .text
; These pointers are used by the installer and
; must be first in the binary
Pointers: dw Int13Start
dw Int15Start
dw PatchArea
dw TotalSize
Int13Start:
; Swap stack
mov [cs:Stack],esp
mov [cs:SavedAX],ax
mov ax,ss
mov [cs:Stack+4],ax
mov ax,cs
mov ss,ax
mov sp,[cs:MyStack]
; See if DL points to our class of device (FD, HD)
push dx
push dx
xor dl,[cs:DriveNo]
pop dx
js .nomatch ; If SF=0, we have a class match here
jz .our_drive ; If ZF=1, we have an exact match
cmp dl,[cs:DriveNo]
jb .nomatch ; Drive < Our drive
dec dl ; Drive > Our drive, adjust drive #
.nomatch:
mov ax,[cs:SavedAX]
pushf
call far [cs:OldInt13]
pushf
push bp
mov bp,sp
cmp byte [cs:SavedAX+1],08h
je .norestoredl
cmp byte [cs:SavedAX+1],15h
jne .restoredl
test byte [bp+4],80h ; Hard disk?
jnz .norestoredl
.restoredl:
mov dl,[bp+4]
.norestoredl:
push ax
push ebx
push ds
mov ax,[bp+2] ; Flags
lds ebx,[cs:Stack]
mov [bx+4],al ; Arithmetric flags
pop ds
pop ebx
pop ax
pop bp
lss esp,[cs:Stack]
iret
.our_drive:
; Set up standard entry frame
push ds
push es
mov ds,ax
mov es,ax
mov ax,[SavedAX]
pushad
mov bp,sp ; Point BP to the entry stack frame
TRACER 'F'
; Note: AH == P_AH here
cmp ah,Int13FuncsMax
jae Invalid_jump
xor al,al ; AL = 0 is standard entry condition
mov di,ax
shr di,7 ; Convert AH to an offset in DI
call [Int13Funcs+di]
Done: ; Standard routine for return
mov P_AX,ax
DoneWeird:
TRACER 'D'
xor bx,bx
mov es,bx
mov bx,[StatusPtr]
mov [es:bx],ah ; Save status
and ah,ah
lds ebx,[Stack]
; This sets the low byte (the arithmetric flags) of the
; FLAGS on stack to either 00h (no flags) or 01h (CF)
; depending on if AH was zero or not.
setnz [bx+4] ; Set CF iff error
popad
pop es
pop ds
lss esp,[cs:Stack]
iret
Reset:
; Reset affects multiple drives, so we need to pass it on
TRACER 'R'
test dl,dl ; Always pass it on if we are resetting HD
js .pass_on ; Bit 7 set
; Some BIOSes get very unhappy if we pass a reset floppy
; command to them and don't actually have any floppies.
; This is a bug, but we have to deal with it nontheless.
; Therefore, if we are the *ONLY* floppy drive, and the
; user didn't request HD reset, then just drop the command.
xor ax,ax ; Bottom of memory
mov es,ax
; BIOS equipment byte, top two bits + 1 == total # of floppies
test byte [es:0x410],0C0h
jz success
; ... otherwise pass it to the BIOS
.pass_on:
pop ax ; Drop return address
popad ; Restore all registers
pop es
pop ds
lss esp,[cs:Stack] ; Restore the stack
and dl,80h ; Clear all but the type bit
jmp far [cs:OldInt13]
Invalid:
pop dx ; Drop return address
Invalid_jump:
TRACER 'I'
mov ah,01h ; Unsupported function
jmp short Done
GetDriveType:
test byte [DriveNo],80h
mov bl,02h ; Type 02h = floppy with changeline
jz .floppy
; Hard disks only...
inc bx ; Type = 03h
mov dx,[DiskSize] ; Return the disk size in sectors
mov P_DX,dx
mov cx,[DiskSize+2]
mov P_CX,cx
.floppy:
mov P_AH,bl ; 02h floppy, 03h hard disk
pop ax ; Drop return address
xor ax,ax ; Success...
jmp short DoneWeird ; But don't stick it into P_AX
GetStatus:
xor ax,ax
mov es,ax
mov bx,[StatusPtr]
mov ah,[bx] ; Copy last status
ret
ReadMult:
TRACER 'm'
Read:
TRACER 'R'
call setup_regs
do_copy:
TRACER '<'
call bcopy
TRACER '>'
movzx ax,P_AL ; AH = 0, AL = transfer count
ret
WriteMult:
TRACER 'M'
Write:
TRACER 'W'
test byte [ConfigFlags],CONFIG_READONLY
jnz .readonly
call setup_regs
xchg esi,edi ; Opposite direction of a Read!
jmp short do_copy
.readonly: mov ah,03h ; Write protected medium
ret
; Verify integrity; just bounds-check
Seek:
Verify:
call setup_regs ; Returns error if appropriate
; And fall through to success
CheckIfReady: ; These are always-successful noop functions
Recalibrate:
InitWithParms:
DetectChange:
SetMode:
success:
xor ax,ax ; Always successful
ret
GetParms:
TRACER 'G'
mov dl,[DriveCnt] ; Cached data
mov P_DL,dl
test byte [DriveNo],80h
jnz .hd
mov P_DI,DPT
mov P_ES,cs
mov bl,[DriveType]
mov P_BL,bl
.hd:
mov ax,[Cylinders]
dec ax ; We report the highest #, not the count
xchg al,ah
shl al,6
or al,[Sectors]
mov P_CX,ax
mov ax,[Heads]
dec ax
mov P_DH,al
;
; Is this MEMDISK installation check?
;
cmp P_HAX,'ME'
jne .notic
cmp P_HCX,'MD'
jne .notic
cmp P_HDX,'IS'
jne .notic
cmp P_HBX,'K?'
jne .notic
; MEMDISK installation check...
mov P_HAX,'!M'
mov P_HCX,'EM'
mov P_HDX,'DI'
mov P_HBX,'SK'
mov P_ES,cs
mov P_DI,MemDisk_Info
.notic:
xor ax,ax
ret
; Set up registers as for a "Read", and compares against disk size
setup_regs:
; Convert a CHS address in P_CX/P_DH into an LBA in eax
; CH = cyl[7:0]
; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8]
; DH = head
movzx ecx,P_CX
movzx ebx,cl ; Sector number
and bl,3Fh
dec ebx ; Sector number is 1-based
cmp bx,[Sectors]
jae .overrun
movzx edi,P_DH ; Head number
movzx eax,word [Heads]
cmp di,ax
jae .overrun
shr cl,6
xchg cl,ch ; Now (E)CX <- cylinder number
mul ecx ; eax <- Heads*cyl# (edx <- 0)
add eax,edi
mul dword [Sectors]
add eax,ebx
; Now eax = LBA, edx = 0
;
; setup_regs continues...
;
; Note: edi[31:16] and ecx[31:16] = 0 already
mov di,P_BX ; Get linear address of target buffer
mov cx,P_ES
shl ecx,4
add edi,ecx ; EDI = address to fetch to
movzx ecx,P_AL ; Sector count
mov esi,eax
add eax,ecx ; LBA of final sector + 1
shl esi,SECTORSIZE_LG2 ; LBA -> byte offset
add esi,[DiskBuf] ; Get address in high memory
cmp eax,[DiskSize] ; Check the high mark against limit
ja .overrun
shl ecx,SECTORSIZE_LG2-2 ; Convert count to 32-bit words
ret
.overrun: pop ax ; Drop setup_regs return address
mov ax,0200h ; Missing address mark
ret ; Return to Done
int15_e820:
cmp edx,534D4150h ; "SMAP"
jne near oldint15
cmp ecx,20 ; Need 20 bytes
jb err86
push ds
push cs
pop ds
and ebx,ebx
jne .renew
mov ebx,E820Table
.renew:
add bx,12 ; Advance to next
mov eax,[bx-4] ; Type
and eax,eax ; Null type?
jz .renew ; If so advance to next
mov [es:di+16],eax
mov eax,[bx-12] ; Start addr (low)
mov [es:di],eax
mov ecx,[bx-8] ; Start addr (high)
mov [es:di+4],ecx
mov eax,[bx] ; End addr (low)
mov ecx,[bx+4] ; End addr (high)
sub eax,[bx-12] ; Derive the length
sbb ecx,[bx-8]
mov [es:di+8],eax ; Length (low)
mov [es:di+12],ecx ; Length (high)
cmp dword [bx+8],-1 ; Type of next = end?
jne .notdone
xor ebx,ebx ; Done with table
.notdone:
mov eax,edx ; "SMAP"
pop ds
mov ecx,20 ; Bytes loaded
int15_success:
mov byte [bp+6], 02h ; Clear CF
pop bp
iret
err86:
mov byte [bp+6], 03h ; Set CF
mov ah,86h
pop bp
iret
Int15Start:
push bp
mov bp,sp
cmp ax,0E820h
je near int15_e820
cmp ax,0E801h
je int15_e801
cmp ax,0E881h
je int15_e881
cmp ah,88h
je int15_88
oldint15: pop bp
jmp far [cs:OldInt15]
int15_e801:
mov ax,[cs:Mem1MB]
mov cx,ax
mov bx,[cs:Mem16MB]
mov dx,bx
jmp short int15_success
int15_e881:
mov eax,[cs:Mem1MB]
mov ecx,eax
mov ebx,[cs:Mem16MB]
mov edx,ebx
jmp short int15_success
int15_88:
mov ax,[cs:MemInt1588]
jmp short int15_success
;
; Routine to copy in/out of high memory
; esi = linear source address
; edi = linear target address
; ecx = 32-bit word count
;
; Assumes cs = ds = es
;
bcopy:
push eax
push ebx
push edx
push ebp
test byte [ConfigFlags],CONFIG_RAW
jz .anymode
smsw ax ; Unprivileged!
test al,01h
jnz .protmode
.realmode:
TRACER 'r'
; We're in real mode, do it outselves
pushfd
push ds
push es
cli
cld
xor ebx,ebx
mov bx,cs
shl ebx,4
lea edx,[Shaker+ebx]
mov [Shaker+2],edx
; Test to see if A20 is enabled or not
xor ax,ax
mov ds,ax
dec ax
mov es,ax
mov ax,[0]
mov bx,ax
xor bx,[es:10h]
not ax
mov [0],ax
mov dx,ax
xor dx,[es:10h]
not ax
mov [0],ax
or dx,bx
push dx ; Save A20 status
jnz .skip_a20e
mov ax,2401h ; Enable A20
int 15h
.skip_a20e:
mov dl,[ConfigFlags]
and dx,CONFIG_BIGRAW
add dx,8
; DX = 16 for BIGRAW, 8 for RAW
; 8 is selector for a 64K flat segment,
; 16 is selector for a 4GB flat segment.
lgdt [cs:Shaker]
mov eax,cr0
or al,01h
mov cr0,eax
mov bx,16 ; Large flat segment
mov ds,bx
mov es,bx
a32 rep movsd
; DX has the appropriate value to put in
; the registers on return
mov ds,dx
mov es,dx
and al,~01h
mov cr0,eax
pop es
pop ds
pop dx ; A20 status
and dx,dx
jnz .skip_a20d
mov ax,2400h ; Disable A20
int 15h
.skip_a20d:
popfd
jmp .done
.protmode:
TRACER 'p'
.anymode:
.copy_loop:
push esi
push edi
push ecx
cmp ecx,4000h
jna .safe_size
mov ecx,4000h
.safe_size:
push ecx ; Transfer size this cycle
mov eax, esi
mov [Mover_src1], si
shr eax, 16
mov [Mover_src1+2], al
mov [Mover_src2], ah
mov eax, edi
mov [Mover_dst1], di
shr eax, 16
mov [Mover_dst1+2], al
mov [Mover_dst2], ah
mov si,Mover
mov ah, 87h
shl cx,1 ; Convert to 16-bit words
int 15h
cli ; Some BIOSes enable interrupts on INT 15h
pop eax ; Transfer size this cycle
pop ecx
pop edi
pop esi
jc .error
lea esi,[esi+4*eax]
lea edi,[edi+4*eax]
sub ecx, eax
jnz .copy_loop
; CF = 0
.error:
.done:
pop ebp
pop edx
pop ebx
pop eax
ret
%ifdef DEBUG_TRACERS
debug_tracer: pushad
pushfd
mov bp,sp
mov bx,[bp+9*4]
mov al,[cs:bx]
inc word [bp+9*4]
mov ah,0Eh
mov bx,7
int 10h
popfd
popad
ret
%endif
section .data
alignb 2
Int13Funcs dw Reset ; 00h - RESET
dw GetStatus ; 01h - GET STATUS
dw Read ; 02h - READ
dw Write ; 03h - WRITE
dw Verify ; 04h - VERIFY
dw Invalid ; 05h - FORMAT TRACK
dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS
dw Invalid ; 07h - FORMAT DRIVE AT TRACK
dw GetParms ; 08h - GET PARAMETERS
dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH DRIVE PARAMETERS
dw Invalid ; 0Ah
dw Invalid ; 0Bh
dw Seek ; 0Ch - SEEK TO CYLINDER
dw Reset ; 0Dh - RESET HARD DISKS
dw Invalid ; 0Eh
dw Invalid ; 0Fh
dw CheckIfReady ; 10h - CHECK IF READY
dw Recalibrate ; 11h - RECALIBRATE
dw Invalid ; 12h
dw Invalid ; 13h
dw Invalid ; 14h
dw GetDriveType ; 15h - GET DRIVE TYPE
dw DetectChange ; 16h - DETECT DRIVE CHANGE
%if 0
dw Invalid ; 17h
dw Invalid ; 18h
dw Invalid ; 19h
dw Invalid ; 1Ah
dw Invalid ; 1Bh
dw Invalid ; 1Ch
dw Invalid ; 1Dh
dw Invalid ; 1Eh
dw Invalid ; 1Fh
dw Invalid ; 20h
dw ReadMult ; 21h - READ MULTIPLE
dw WriteMult ; 22h - WRITE MULTIPLE
dw SetMode ; 23h - SET CONTROLLER FEATURES
dw SetMode ; 24h - SET MULTIPLE MODE
dw Invalid ; 25h - IDENTIFY DRIVE
dw Invalid ; 26h
dw Invalid ; 27h
dw Invalid ; 28h
dw Invalid ; 29h
dw Invalid ; 2Ah
dw Invalid ; 2Bh
dw Invalid ; 2Ch
dw Invalid ; 2Dh
dw Invalid ; 2Eh
dw Invalid ; 2Fh
dw Invalid ; 30h
dw Invalid ; 31h
dw Invalid ; 32h
dw Invalid ; 33h
dw Invalid ; 34h
dw Invalid ; 35h
dw Invalid ; 36h
dw Invalid ; 37h
dw Invalid ; 38h
dw Invalid ; 39h
dw Invalid ; 3Ah
dw Invalid ; 3Bh
dw Invalid ; 3Ch
dw Invalid ; 3Dh
dw Invalid ; 3Eh
dw Invalid ; 3Fh
dw Invalid ; 40h
dw EDDPresence ; 41h - EDD PRESENCE DETECT
dw EDDRead ; 42h - EDD READ
dw EDDWrite ; 43h - EDD WRITE
dw EDDVerify ; 44h - EDD VERIFY
dw Invalid ; 45h - EDD LOCK/UNLOCK MEDIA
dw Invalid ; 46h - EDD EJECT
dw EDDSeek ; 47h - EDD SEEK
dw EDDGetParms ; 48h - EDD GET PARAMETERS
%endif
Int13FuncsEnd equ $
Int13FuncsMax equ (Int13FuncsEnd-Int13Funcs) >> 1
alignb 8, db 0
Shaker dw ShakerEnd-$
dd 0 ; Pointer to self
dw 0
Shaker_RMDS: dd 0x0000ffff ; 64K data segment
dd 0x00009300
Shaker_DS: dd 0x0000ffff ; 4GB data segment
dd 0x008f9300
ShakerEnd equ $
alignb 8, db 0
Mover dd 0, 0, 0, 0 ; Must be zero
dw 0ffffh ; 64 K segment size
Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy
db 93h ; Access rights
db 00h ; Extended access rights
Mover_src2: db 0 ; High 8 bits of source addy
dw 0ffffh ; 64 K segment size
Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy
db 93h ; Access rights
db 00h ; Extended access rights
Mover_dst2: db 0 ; High 8 bits of source addy
Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS
alignb 4, db 0
MemDisk_Info equ $ ; Pointed to by installation check
MDI_Bytes dw 27 ; Total bytes in MDI structure
MDI_Version db VER_MINOR, VER_MAJOR ; MEMDISK version
PatchArea equ $ ; This gets filled in by the installer
DiskBuf dd 0 ; Linear address of high memory disk
DiskSize dd 0 ; Size of disk in blocks
CommandLine dw 0, 0 ; Far pointer to saved command line
OldInt13 dd 0 ; INT 13h in chain
OldInt15 dd 0 ; INT 15h in chain
OldDosMem dw 0 ; Old position of DOS mem end
BootLoaderID db 0 ; Boot loader ID from header
; ---- MDI structure ends here ---
db 0, 0, 0 ; pad
MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
Cylinders dw 0 ; Cylinder count
Heads dw 0 ; Head count
Sectors dd 0 ; Sector count (zero-extended)
Mem1MB dd 0 ; 1MB-16MB memory amount (1K)
Mem16MB dd 0 ; 16MB-4G memory amount (64K)
DriveNo db 0 ; Our drive number
DriveType db 0 ; Our drive type (floppies)
DriveCnt db 0 ; Drive count (from the BIOS)
ConfigFlags db 0 ; Bit 0 - readonly
MyStack dw 0 ; Offset of stack
StatusPtr dw 0 ; Where to save status (zeroseg ptr)
DPT times 16 db 0 ; BIOS parameter table pointer (floppies)
; End patch area
Stack dd 0 ; Saved SS:ESP on invocation
dw 0
SavedAX dw 0 ; AX saved on invocation
alignb 4, db 0 ; We *MUST* end on a dword boundary
E820Table equ $ ; The installer loads the E820 table here
TotalSize equ $ ; End pointer

Binary file not shown.

View File

@@ -0,0 +1,186 @@
$Id: memdisk.doc,v 1.17 2005/04/29 06:04:45 hpa Exp $
[This documentation is rather crufty at the moment.]
MEMDISK is meant to allow booting legacy operating systems via PXE,
and as a workaround for BIOSes where ISOLINUX image support doesn't
work.
MEMDISK simulates a disk by claiming a chunk of high memory for the
disk and a (very small - 2K typical) chunk of low (DOS) memory for the
driver itself, then hooking the INT 13h (disk driver) and INT 15h
(memory query) BIOS interrupts.
To use it, type on the SYSLINUX command line:
memdisk initrd=diskimg.img
... where diskimg.img is the disk image you want to boot from.
[Obviously, the memdisk binary as well as your disk image file need to
be present in the boot image directory.]
... or add to your syslinux.cfg/pxelinux.cfg/isolinux.cfg something like:
label dos
kernel memdisk
append initrd=dosboot.img
Note the following:
a) The disk image can be uncompressed or compressed with gzip or zip.
b) If the disk image is one of the following sizes, it's assumed to be a
floppy image:
368,640 bytes - 360K floppy
737,280 bytes - 720K floppy
1,222,800 bytes - 1200K floppy
1,474,560 bytes - 1440K floppy
1,720,320 bytes - 1680K floppy (common extended format)
1,763,328 bytes - 1722K floppy (common extended format)
2,949,120 bytes - 2880K floppy
3,932,160 bytes - 3840K floppy (extended format)
For any other size, the image is assumed to be a hard disk image,
and should typically have an MBR and a partition table. It may
optionally have a DOSEMU geometry header; in which case the header
is used to determine the C/H/S geometry of the disk. Otherwise,
the geometry is determined by examining the partition table, so the
entire image should be partitioned for proper operation (it may be
divided between multiple partitions, however.)
You can also specify the geometry manually with the following command
line options:
c=<number> Specify number of cylinders (max 1024[*])
h=<number> Specify number of heads (max 256[*])
s=<number> Specify number of sectors (max 63)
floppy The image is a floppy image
harddisk The image is a hard disk image
[*] MS-DOS only allows max 255 heads, and only allows 255 cylinders
on floppy disks.
c) The disk is normally writable (although, of course, there is
nothing backing it up, so it only lasts until reset.) If you want,
you can mimic a write-protected disk by specifying the command line
option:
ro Disk is readonly
d) MEMDISK normally uses the BIOS "INT 15h mover" API to access high
memory. This is well-behaved with extended memory managers which load
later. Unfortunately it appears that the "DOS boot disk" from
WinME/XP *deliberately* crash the system when this API is invoked.
The following command-line options tells MEMDISK to enter protected
mode directly, whenever possible:
raw Use raw access to protected mode memory.
bigraw Use raw access to protected mode memory, and leave the
CPU in "big real" mode afterwards.
Some interesting things to note:
If you're using MEMDISK to boot DOS from a CD-ROM (using ISOLINUX),
you might find the generic El Torito CD-ROM driver by Gary Tong and
Bart Lagerweij useful:
http://www.nu2.nu/eltorito/
Similarly, if you're booting DOS over the network using PXELINUX, you
can use the "keeppxe" option and use the generic PXE (UNDI) NDIS
network driver, which is part of the PROBOOT.EXE distribution from
Intel:
http://www.intel.com/support/network/adapter/1000/software.htm
Additional technical information:
Starting with version 2.08, MEMDISK now supports an installation check
API. This works as follows:
EAX = 454D08xxh ("ME") (08h = parameter query)
ECX = 444Dxxxxh ("MD")
EDX = 5349xxnnh ("IS") (nn = drive #)
EBX = 3F4Bxxxxh ("K?")
INT 13h
If drive nn is a MEMDISK, the registers will contain:
EAX = 4D21xxxxh ("!M")
ECX = 4D45xxxxh ("EM")
EDX = 4944xxxxh ("DI")
EBX = 4B53xxxxh ("SK")
ES:DI -> MEMDISK info structures
The low parts of EAX/ECX/EDX/EBX have the normal return values for INT
13h, AH=08h, i.e. information of the disk geometry etc.
See Ralf Brown's interrupt list,
http://www.cs.cmu.edu/afs/cs.cmu.edu/user/ralf/pub/WWW/files.html or
http://www.ctyme.com/rbrown.htm, for a detailed description.
The MEMDISK info structure currently contains:
[ES:DI] word Total size of structure (currently 27 bytes)
[ES:DI+2] byte MEMDISK minor version
[ES:DI+3] byte MEMDISK major version
[ES:DI+4] dword Pointer to MEMDISK data in high memory
[ES:DI+8] dword Size of MEMDISK data in 512-byte sectors
[ES:DI+12] 16:16 Far pointer to command line
[ES:DI+16] 16:16 Old INT 13h pointer
[ES:DI+20] 16:16 Old INT 15h pointer
[ES:DI+24] word Amount of DOS memory before MEMDISK loaded
[ES:DI+26] byte Boot loader ID
MEMDISK 3.00 and higher has the size of this structure as 27; earlier
versions had size 26 and did not include the boot loader ID.
In addition, the following fields are available at [ES:0]:
[ES:0] word Offset of INT 13h routine (segment == ES)
[ES:2] word Offset of INT 15h routine (segment == ES)
The program mdiskchk.c in the sample directory is an example on how
this API can be used.
The following code can be used to "disable" MEMDISK. Note that it
does not free the handler in DOS memory, and that running this from
DOS will probably crash your machine (DOS doesn't like drives
suddenly disappearing from underneath):
mov eax, 454D0800h
mov ecx, 444D0000h
mov edx, 53490000h + drive #
mov ebx, 3F4B0000h
int 13h
shr eax, 16
cmp ax, 4D21h
jne not_memdisk
shr ecx, 16
cmp cx, 4D45h
jne not_memdisk
shr edx, 16
cmp dx, 4944h
jne not_memdisk
shr ebx, 16
cmp bx, 4B53h
jne not_memdisk
cli
mov bx,[es:0] ; INT 13h handler offset
mov eax,[es:di+16] ; Old INT 13h handler
mov byte [es:bx], 0EAh ; FAR JMP
mov [es:bx+1], eax
mov bx,[es:2] ; INT 15h handler offset
mov eax,[es:di+20] ; Old INT 15h handler
mov byte [es:bx], 0EAh ; FAR JMP
mov [es:bx+1], eax
sti

View File

@@ -0,0 +1,74 @@
#ident "$Id: memdisk.h,v 1.9 2005/03/08 18:39:32 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2003 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.
*
* ----------------------------------------------------------------------- */
/*
* memdisk.h
*
* Miscellaneous header definitions
*/
#ifndef MEMDISK_H
#define MEMDISK_H
/* We use the com32 interface for calling 16-bit code */
#include <com32.h>
/* The real-mode segment */
#define LOW_SEG 0x0800
typedef void (*syscall_t)(uint8_t, com32sys_t *, com32sys_t *);
extern syscall_t syscall;
extern void *sys_bounce;
/* What to call when we're dead */
extern void __attribute__((noreturn)) die(void);
/* Standard routines */
#define memcpy(a,b,c) __builtin_memcpy(a,b,c)
#define memset(a,b,c) __builtin_memset(a,b,c)
#define strcpy(a,b) __builtin_strcpy(a,b)
#define strlen(a) __builtin_strlen(a)
/* memcpy() but returns a pointer to end of buffer */
static inline void *
memcpy_endptr(void *__d, const void *__s, unsigned int __n)
{
memcpy(__d, __s, __n);
return (void *)((char *)__d + __n);
}
/* memcmp() */
static inline int
memcmp(const void *__a, const void *__b, unsigned int __n)
{
const unsigned char *__aa = __a;
const unsigned char *__bb = __b;
int __d;
while ( __n ) {
__d = *__bb++ - *__aa++;
if ( __d )
return __d;
}
return 0;
}
/* Decompression */
extern int check_zip(void *indata, uint32_t size, uint32_t *zbytes_p,
uint32_t *dbytes_p, uint32_t *orig_crc,
uint32_t *offset_p);
extern void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
uint32_t orig_crc, void *target);
#endif

View File

@@ -0,0 +1,764 @@
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; $Id: memdisk.asm,v 1.29 2005/04/29 06:08:03 hpa Exp $
3 ; ****************************************************************************
4 ;
5 ; memdisk.asm
6 ;
7 ; A program to emulate an INT 13h disk BIOS from a "disk" in extended
8 ; memory.
9 ;
10 ; Copyright (C) 2001-2004 H. Peter Anvin
11 ;
12 ; This program is free software; you can redistribute it and/or modify
13 ; it under the terms of the GNU General Public License as published by
14 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
15 ; Boston MA 02111-1307, USA; either version 2 of the License, or
16 ; (at your option) any later version; incorporated herein by reference.
17 ;
18 ; ****************************************************************************
19
20 %ifndef DEPEND
21 %include "../version.gen"
22 <1> %define VERSION "3.09"
23 <1> %define VER_MAJOR 3
24 <1> %define VER_MINOR 9
25 %endif
26
27 ; %define DEBUG_TRACERS ; Uncomment to get debugging tracers
28
29 %ifdef DEBUG_TRACERS
30
31 %macro TRACER 1
32 call debug_tracer
33 db %1
34 %endmacro
35
36 %else ; DEBUG_TRACERS
37
38 %macro TRACER 1
39 %endmacro
40
41 %endif ; DEBUG_TRACERS
42
43 %define CONFIG_READONLY 0x01
44 %define CONFIG_RAW 0x02
45 %define CONFIG_BIGRAW 0x08 ; MUST be 8!
46
47 org 0h
48
49 %define SECTORSIZE_LG2 9 ; log2(sector size)
50 %define SECTORSIZE (1 << SECTORSIZE_LG2)
51
52 ; Parameter registers definition; this is the definition
53 ; of the stack frame.
54 %define P_DS word [bp+34]
55 %define P_ES word [bp+32]
56 %define P_EAX dword [bp+28]
57 %define P_HAX word [bp+30]
58 %define P_AX word [bp+28]
59 %define P_AL byte [bp+28]
60 %define P_AH byte [bp+29]
61 %define P_ECX dword [bp+24]
62 %define P_HCX word [bp+26]
63 %define P_CX word [bp+24]
64 %define P_CL byte [bp+24]
65 %define P_CH byte [bp+25]
66 %define P_EDX dword [bp+20]
67 %define P_HDX word [bp+22]
68 %define P_DX word [bp+20]
69 %define P_DL byte [bp+20]
70 %define P_DH byte [bp+21]
71 %define P_EBX dword [bp+16]
72 %define P_HBX word [bp+18]
73 %define P_HBXL byte [bp+18]
74 %define P_BX word [bp+16]
75 %define P_BL byte [bp+16]
76 %define P_BH byte [bp+17]
77 %define P_EBP dword [bp+8]
78 %define P_BP word [bp+8]
79 %define P_ESI dword [bp+4]
80 %define P_SI word [bp+4]
81 %define P_EDI dword [bp]
82 %define P_DI word [bp]
83
84 section .text
85 ; These pointers are used by the installer and
86 ; must be first in the binary
87 00000000 [0800] Pointers: dw Int13Start
88 00000002 [8602] dw Int15Start
89 00000004 [7C00] dw PatchArea
90 00000006 [C800] dw TotalSize
91
92 Int13Start:
93 ; Swap stack
94 00000008 2E668926[C000] mov [cs:Stack],esp
95 0000000E 2EA3[C600] mov [cs:SavedAX],ax
96 00000012 8CD0 mov ax,ss
97 00000014 2EA3[C400] mov [cs:Stack+4],ax
98 00000018 8CC8 mov ax,cs
99 0000001A 8ED0 mov ss,ax
100 0000001C 2E8B26[AC00] mov sp,[cs:MyStack]
101
102 ; See if DL points to our class of device (FD, HD)
103 00000021 52 push dx
104 00000022 52 push dx
105 00000023 2E3216[A800] xor dl,[cs:DriveNo]
106 00000028 5A pop dx
107 00000029 780B js .nomatch ; If SF=0, we have a class match here
108 0000002B 744D jz .our_drive ; If ZF=1, we have an exact match
109 0000002D 2E3A16[A800] cmp dl,[cs:DriveNo]
110 00000032 7202 jb .nomatch ; Drive < Our drive
111 00000034 FECA dec dl ; Drive > Our drive, adjust drive #
112 .nomatch:
113 00000036 2EA1[C600] mov ax,[cs:SavedAX]
114 0000003A 9C pushf
115 0000003B 2EFF1E[8800] call far [cs:OldInt13]
116 00000040 9C pushf
117 00000041 55 push bp
118 00000042 89E5 mov bp,sp
119 00000044 2E803E[C700]08 cmp byte [cs:SavedAX+1],08h
120 0000004A 7411 je .norestoredl
121 0000004C 2E803E[C700]15 cmp byte [cs:SavedAX+1],15h
122 00000052 7506 jne .restoredl
123 00000054 F6460480 test byte [bp+4],80h ; Hard disk?
124 00000058 7503 jnz .norestoredl
125 .restoredl:
126 0000005A 8A5604 mov dl,[bp+4]
127 .norestoredl:
128 0000005D 50 push ax
129 0000005E 6653 push ebx
130 00000060 1E push ds
131 00000061 8B4602 mov ax,[bp+2] ; Flags
132 00000064 2E66C51E[C000] lds ebx,[cs:Stack]
133 0000006A 884704 mov [bx+4],al ; Arithmetric flags
134 0000006D 1F pop ds
135 0000006E 665B pop ebx
136 00000070 58 pop ax
137 00000071 5D pop bp
138 00000072 2E660FB226[C000] lss esp,[cs:Stack]
139 00000079 CF iret
140
141 .our_drive:
142 ; Set up standard entry frame
143 0000007A 1E push ds
144 0000007B 06 push es
145 0000007C 8ED8 mov ds,ax
146 0000007E 8EC0 mov es,ax
147 00000080 A1[C600] mov ax,[SavedAX]
148 00000083 6660 pushad
149 00000085 89E5 mov bp,sp ; Point BP to the entry stack frame
150 TRACER 'F'
151 ; Note: AH == P_AH here
152 00000087 80FC17 cmp ah,Int13FuncsMax
153 0000008A 7355 jae Invalid_jump
154 0000008C 30C0 xor al,al ; AL = 0 is standard entry condition
155 0000008E 89C7 mov di,ax
156 00000090 C1EF07 shr di,7 ; Convert AH to an offset in DI
157 00000093 FF95[0000] call [Int13Funcs+di]
158
159 Done: ; Standard routine for return
160 00000097 89461C mov P_AX,ax
161 DoneWeird:
162 TRACER 'D'
163 0000009A 31DB xor bx,bx
164 0000009C 8EC3 mov es,bx
165 0000009E 8B1E[AE00] mov bx,[StatusPtr]
166 000000A2 268827 mov [es:bx],ah ; Save status
167 000000A5 20E4 and ah,ah
168
169 000000A7 66C51E[C000] lds ebx,[Stack]
170 ; This sets the low byte (the arithmetric flags) of the
171 ; FLAGS on stack to either 00h (no flags) or 01h (CF)
172 ; depending on if AH was zero or not.
173 000000AC 0F954704 setnz [bx+4] ; Set CF iff error
174 000000B0 6661 popad
175 000000B2 07 pop es
176 000000B3 1F pop ds
177 000000B4 2E660FB226[C000] lss esp,[cs:Stack]
178 000000BB CF iret
179
180 Reset:
181 ; Reset affects multiple drives, so we need to pass it on
182 TRACER 'R'
183 000000BC 84D2 test dl,dl ; Always pass it on if we are resetting HD
184 000000BE 780C js .pass_on ; Bit 7 set
185 ; Some BIOSes get very unhappy if we pass a reset floppy
186 ; command to them and don't actually have any floppies.
187 ; This is a bug, but we have to deal with it nontheless.
188 ; Therefore, if we are the *ONLY* floppy drive, and the
189 ; user didn't request HD reset, then just drop the command.
190 000000C0 31C0 xor ax,ax ; Bottom of memory
191 000000C2 8EC0 mov es,ax
192 ; BIOS equipment byte, top two bits + 1 == total # of floppies
193 000000C4 26F6061004C0 test byte [es:0x410],0C0h
194 000000CA 7464 jz success
195 ; ... otherwise pass it to the BIOS
196 .pass_on:
197 000000CC 58 pop ax ; Drop return address
198 000000CD 6661 popad ; Restore all registers
199 000000CF 07 pop es
200 000000D0 1F pop ds
201 000000D1 2E660FB226[C000] lss esp,[cs:Stack] ; Restore the stack
202 000000D8 80E280 and dl,80h ; Clear all but the type bit
203 000000DB 2EFF2E[8800] jmp far [cs:OldInt13]
204
205
206 Invalid:
207 000000E0 5A pop dx ; Drop return address
208 Invalid_jump:
209 TRACER 'I'
210 000000E1 B401 mov ah,01h ; Unsupported function
211 000000E3 EBB2 jmp short Done
212
213 GetDriveType:
214 000000E5 F606[A800]80 test byte [DriveNo],80h
215 000000EA B302 mov bl,02h ; Type 02h = floppy with changeline
216 000000EC 740F jz .floppy
217 ; Hard disks only...
218 000000EE 43 inc bx ; Type = 03h
219 000000EF 8B16[8000] mov dx,[DiskSize] ; Return the disk size in sectors
220 000000F3 895614 mov P_DX,dx
221 000000F6 8B0E[8200] mov cx,[DiskSize+2]
222 000000FA 894E18 mov P_CX,cx
223 .floppy:
224 000000FD 885E1D mov P_AH,bl ; 02h floppy, 03h hard disk
225 00000100 58 pop ax ; Drop return address
226 00000101 31C0 xor ax,ax ; Success...
227 00000103 EB95 jmp short DoneWeird ; But don't stick it into P_AX
228
229 GetStatus:
230 00000105 31C0 xor ax,ax
231 00000107 8EC0 mov es,ax
232 00000109 8B1E[AE00] mov bx,[StatusPtr]
233 0000010D 8A27 mov ah,[bx] ; Copy last status
234 0000010F C3 ret
235
236 ReadMult:
237 TRACER 'm'
238 Read:
239 TRACER 'R'
240 00000110 E88F00 call setup_regs
241 do_copy:
242 TRACER '<'
243 00000113 E8B701 call bcopy
244 TRACER '>'
245 00000116 0FB6461C movzx ax,P_AL ; AH = 0, AL = transfer count
246 0000011A C3 ret
247
248 WriteMult:
249 TRACER 'M'
250 Write:
251 TRACER 'W'
252 0000011B F606[AB00]01 test byte [ConfigFlags],CONFIG_READONLY
253 00000120 7508 jnz .readonly
254 00000122 E87D00 call setup_regs
255 00000125 6687F7 xchg esi,edi ; Opposite direction of a Read!
256 00000128 EBE9 jmp short do_copy
257 0000012A B403 .readonly: mov ah,03h ; Write protected medium
258 0000012C C3 ret
259
260 ; Verify integrity; just bounds-check
261 Seek:
262 Verify:
263 0000012D E87200 call setup_regs ; Returns error if appropriate
264 ; And fall through to success
265
266 CheckIfReady: ; These are always-successful noop functions
267 Recalibrate:
268 InitWithParms:
269 DetectChange:
270 SetMode:
271 success:
272 00000130 31C0 xor ax,ax ; Always successful
273 00000132 C3 ret
274
275 GetParms:
276 TRACER 'G'
277 00000133 8A16[AA00] mov dl,[DriveCnt] ; Cached data
278 00000137 885614 mov P_DL,dl
279 0000013A F606[A800]80 test byte [DriveNo],80h
280 0000013F 750F jnz .hd
281 00000141 C74600[B000] mov P_DI,DPT
282 00000146 8C4E20 mov P_ES,cs
283 00000149 8A1E[A900] mov bl,[DriveType]
284 0000014D 885E10 mov P_BL,bl
285 .hd:
286 00000150 A1[9800] mov ax,[Cylinders]
287 00000153 48 dec ax ; We report the highest #, not the count
288 00000154 86C4 xchg al,ah
289 00000156 C0E006 shl al,6
290 00000159 0A06[9C00] or al,[Sectors]
291 0000015D 894618 mov P_CX,ax
292 00000160 A1[9A00] mov ax,[Heads]
293 00000163 48 dec ax
294 00000164 884615 mov P_DH,al
295
296 ;
297 ; Is this MEMDISK installation check?
298 ;
299 00000167 817E1E4D45 cmp P_HAX,'ME'
300 0000016C 7531 jne .notic
301 0000016E 817E1A4D44 cmp P_HCX,'MD'
302 00000173 752A jne .notic
303 00000175 817E164953 cmp P_HDX,'IS'
304 0000017A 7523 jne .notic
305 0000017C 817E124B3F cmp P_HBX,'K?'
306 00000181 751C jne .notic
307
308 ; MEMDISK installation check...
309 00000183 C7461E214D mov P_HAX,'!M'
310 00000188 C7461A454D mov P_HCX,'EM'
311 0000018D C746164449 mov P_HDX,'DI'
312 00000192 C74612534B mov P_HBX,'SK'
313 00000197 8C4E20 mov P_ES,cs
314 0000019A C74600[7800] mov P_DI,MemDisk_Info
315
316 .notic:
317 0000019F 31C0 xor ax,ax
318 000001A1 C3 ret
319
320 ; Set up registers as for a "Read", and compares against disk size
321 setup_regs:
322
323 ; Convert a CHS address in P_CX/P_DH into an LBA in eax
324 ; CH = cyl[7:0]
325 ; CL[0:5] = sector (1-based) CL[7:6] = cyl[9:8]
326 ; DH = head
327 000001A2 660FB74E18 movzx ecx,P_CX
328 000001A7 660FB6D9 movzx ebx,cl ; Sector number
329 000001AB 80E33F and bl,3Fh
330 000001AE 664B dec ebx ; Sector number is 1-based
331 000001B0 3B1E[9C00] cmp bx,[Sectors]
332 000001B4 734F jae .overrun
333 000001B6 660FB67E15 movzx edi,P_DH ; Head number
334 000001BB 660FB706[9A00] movzx eax,word [Heads]
335 000001C1 39C7 cmp di,ax
336 000001C3 7340 jae .overrun
337 000001C5 C0E906 shr cl,6
338 000001C8 86CD xchg cl,ch ; Now (E)CX <- cylinder number
339 000001CA 66F7E1 mul ecx ; eax <- Heads*cyl# (edx <- 0)
340 000001CD 6601F8 add eax,edi
341 000001D0 66F726[9C00] mul dword [Sectors]
342 000001D5 6601D8 add eax,ebx
343 ; Now eax = LBA, edx = 0
344
345 ;
346 ; setup_regs continues...
347 ;
348 ; Note: edi[31:16] and ecx[31:16] = 0 already
349 000001D8 8B7E10 mov di,P_BX ; Get linear address of target buffer
350 000001DB 8B4E20 mov cx,P_ES
351 000001DE 66C1E104 shl ecx,4
352 000001E2 6601CF add edi,ecx ; EDI = address to fetch to
353 000001E5 660FB64E1C movzx ecx,P_AL ; Sector count
354 000001EA 6689C6 mov esi,eax
355 000001ED 6601C8 add eax,ecx ; LBA of final sector + 1
356 000001F0 66C1E609 shl esi,SECTORSIZE_LG2 ; LBA -> byte offset
357 000001F4 660336[7C00] add esi,[DiskBuf] ; Get address in high memory
358 000001F9 663B06[8000] cmp eax,[DiskSize] ; Check the high mark against limit
359 000001FE 7705 ja .overrun
360 00000200 66C1E107 shl ecx,SECTORSIZE_LG2-2 ; Convert count to 32-bit words
361 00000204 C3 ret
362
363 00000205 58 .overrun: pop ax ; Drop setup_regs return address
364 00000206 B80002 mov ax,0200h ; Missing address mark
365 00000209 C3 ret ; Return to Done
366
367 int15_e820:
368 0000020A 6681FA50414D53 cmp edx,534D4150h ; "SMAP"
369 00000211 0F858A00 jne near oldint15
370 00000215 6683F914 cmp ecx,20 ; Need 20 bytes
371 00000219 7263 jb err86
372 0000021B 1E push ds
373 0000021C 0E push cs
374 0000021D 1F pop ds
375 0000021E 6621DB and ebx,ebx
376 00000221 7506 jne .renew
377 00000223 66BB[C8000000] mov ebx,E820Table
378 .renew:
379 00000229 83C30C add bx,12 ; Advance to next
380 0000022C 668B47FC mov eax,[bx-4] ; Type
381 00000230 6621C0 and eax,eax ; Null type?
382 00000233 74F4 jz .renew ; If so advance to next
383 00000235 2666894510 mov [es:di+16],eax
384 0000023A 668B47F4 mov eax,[bx-12] ; Start addr (low)
385 0000023E 26668905 mov [es:di],eax
386 00000242 668B4FF8 mov ecx,[bx-8] ; Start addr (high)
387 00000246 2666894D04 mov [es:di+4],ecx
388 0000024B 668B07 mov eax,[bx] ; End addr (low)
389 0000024E 668B4F04 mov ecx,[bx+4] ; End addr (high)
390 00000252 662B47F4 sub eax,[bx-12] ; Derive the length
391 00000256 661B4FF8 sbb ecx,[bx-8]
392 0000025A 2666894508 mov [es:di+8],eax ; Length (low)
393 0000025F 2666894D0C mov [es:di+12],ecx ; Length (high)
394 00000264 66837F08FF cmp dword [bx+8],-1 ; Type of next = end?
395 00000269 7503 jne .notdone
396 0000026B 6631DB xor ebx,ebx ; Done with table
397 .notdone:
398 0000026E 6689D0 mov eax,edx ; "SMAP"
399 00000271 1F pop ds
400 00000272 66B914000000 mov ecx,20 ; Bytes loaded
401 int15_success:
402 00000278 C6460602 mov byte [bp+6], 02h ; Clear CF
403 0000027C 5D pop bp
404 0000027D CF iret
405
406 err86:
407 0000027E C6460603 mov byte [bp+6], 03h ; Set CF
408 00000282 B486 mov ah,86h
409 00000284 5D pop bp
410 00000285 CF iret
411
412 Int15Start:
413 00000286 55 push bp
414 00000287 89E5 mov bp,sp
415 00000289 3D20E8 cmp ax,0E820h
416 0000028C 0F847AFF je near int15_e820
417 00000290 3D01E8 cmp ax,0E801h
418 00000293 7410 je int15_e801
419 00000295 3D81E8 cmp ax,0E881h
420 00000298 741A je int15_e881
421 0000029A 80FC88 cmp ah,88h
422 0000029D 7428 je int15_88
423 0000029F 5D oldint15: pop bp
424 000002A0 2EFF2E[8C00] jmp far [cs:OldInt15]
425
426 int15_e801:
427 000002A5 2EA1[A000] mov ax,[cs:Mem1MB]
428 000002A9 89C1 mov cx,ax
429 000002AB 2E8B1E[A400] mov bx,[cs:Mem16MB]
430 000002B0 89DA mov dx,bx
431 000002B2 EBC4 jmp short int15_success
432
433 int15_e881:
434 000002B4 2E66A1[A000] mov eax,[cs:Mem1MB]
435 000002B9 6689C1 mov ecx,eax
436 000002BC 2E668B1E[A400] mov ebx,[cs:Mem16MB]
437 000002C2 6689DA mov edx,ebx
438 000002C5 EBB1 jmp short int15_success
439
440 int15_88:
441 000002C7 2EA1[9600] mov ax,[cs:MemInt1588]
442 000002CB EBAB jmp short int15_success
443
444 ;
445 ; Routine to copy in/out of high memory
446 ; esi = linear source address
447 ; edi = linear target address
448 ; ecx = 32-bit word count
449 ;
450 ; Assumes cs = ds = es
451 ;
452 bcopy:
453 000002CD 6650 push eax
454 000002CF 6653 push ebx
455 000002D1 6652 push edx
456 000002D3 6655 push ebp
457
458 000002D5 F606[AB00]02 test byte [ConfigFlags],CONFIG_RAW
459 000002DA 0F848D00 jz .anymode
460
461 000002DE 0F01E0 smsw ax ; Unprivileged!
462 000002E1 A801 test al,01h
463 000002E3 0F858400 jnz .protmode
464
465 .realmode:
466 TRACER 'r'
467 ; We're in real mode, do it outselves
468
469 000002E7 669C pushfd
470 000002E9 1E push ds
471 000002EA 06 push es
472
473 000002EB FA cli
474 000002EC FC cld
475
476 000002ED 6631DB xor ebx,ebx
477 000002F0 8CCB mov bx,cs
478 000002F2 66C1E304 shl ebx,4
479 000002F6 66678D93[30000000] lea edx,[Shaker+ebx]
480 000002FE 668916[3200] mov [Shaker+2],edx
481
482 ; Test to see if A20 is enabled or not
483 00000303 31C0 xor ax,ax
484 00000305 8ED8 mov ds,ax
485 00000307 48 dec ax
486 00000308 8EC0 mov es,ax
487
488 0000030A A10000 mov ax,[0]
489 0000030D 89C3 mov bx,ax
490 0000030F 26331E1000 xor bx,[es:10h]
491 00000314 F7D0 not ax
492 00000316 A30000 mov [0],ax
493 00000319 89C2 mov dx,ax
494 0000031B 2633161000 xor dx,[es:10h]
495 00000320 F7D0 not ax
496 00000322 A30000 mov [0],ax
497
498 00000325 09DA or dx,bx
499 00000327 52 push dx ; Save A20 status
500 00000328 7505 jnz .skip_a20e
501
502 0000032A B80124 mov ax,2401h ; Enable A20
503 0000032D CD15 int 15h
504 .skip_a20e:
505 0000032F 8A16[AB00] mov dl,[ConfigFlags]
506 00000333 83E208 and dx,CONFIG_BIGRAW
507 00000336 83C208 add dx,8
508 ; DX = 16 for BIGRAW, 8 for RAW
509 ; 8 is selector for a 64K flat segment,
510 ; 16 is selector for a 4GB flat segment.
511
512 00000339 2E0F0116[3000] lgdt [cs:Shaker]
513 0000033F 0F20C0 mov eax,cr0
514 00000342 0C01 or al,01h
515 00000344 0F22C0 mov cr0,eax
516
517 00000347 BB1000 mov bx,16 ; Large flat segment
518 0000034A 8EDB mov ds,bx
519 0000034C 8EC3 mov es,bx
520
521 0000034E 67F366A5 a32 rep movsd
522
523 ; DX has the appropriate value to put in
524 ; the registers on return
525 00000352 8EDA mov ds,dx
526 00000354 8EC2 mov es,dx
527
528 00000356 24FE and al,~01h
529 00000358 0F22C0 mov cr0,eax
530
531 0000035B 07 pop es
532 0000035C 1F pop ds
533
534 0000035D 5A pop dx ; A20 status
535 0000035E 21D2 and dx,dx
536 00000360 7505 jnz .skip_a20d
537 00000362 B80024 mov ax,2400h ; Disable A20
538 00000365 CD15 int 15h
539 .skip_a20d:
540 00000367 669D popfd
541 00000369 EB5E jmp .done
542
543 .protmode:
544 TRACER 'p'
545 .anymode:
546
547 .copy_loop:
548 0000036B 6656 push esi
549 0000036D 6657 push edi
550 0000036F 6651 push ecx
551 00000371 6681F900400000 cmp ecx,4000h
552 00000378 7606 jna .safe_size
553 0000037A 66B900400000 mov ecx,4000h
554 .safe_size:
555 00000380 6651 push ecx ; Transfer size this cycle
556 00000382 6689F0 mov eax, esi
557 00000385 8936[5A00] mov [Mover_src1], si
558 00000389 66C1E810 shr eax, 16
559 0000038D A2[5C00] mov [Mover_src1+2], al
560 00000390 8826[5F00] mov [Mover_src2], ah
561 00000394 6689F8 mov eax, edi
562 00000397 893E[6200] mov [Mover_dst1], di
563 0000039B 66C1E810 shr eax, 16
564 0000039F A2[6400] mov [Mover_dst1+2], al
565 000003A2 8826[6700] mov [Mover_dst2], ah
566 000003A6 BE[4800] mov si,Mover
567 000003A9 B487 mov ah, 87h
568 000003AB D1E1 shl cx,1 ; Convert to 16-bit words
569 000003AD CD15 int 15h
570 000003AF FA cli ; Some BIOSes enable interrupts on INT 15h
571 000003B0 6658 pop eax ; Transfer size this cycle
572 000003B2 6659 pop ecx
573 000003B4 665F pop edi
574 000003B6 665E pop esi
575 000003B8 720F jc .error
576 000003BA 66678D3486 lea esi,[esi+4*eax]
577 000003BF 66678D3C87 lea edi,[edi+4*eax]
578 000003C4 6629C1 sub ecx, eax
579 000003C7 75A2 jnz .copy_loop
580 ; CF = 0
581 .error:
582 .done:
583 000003C9 665D pop ebp
584 000003CB 665A pop edx
585 000003CD 665B pop ebx
586 000003CF 6658 pop eax
587 000003D1 C3 ret
588
589 %ifdef DEBUG_TRACERS
590 debug_tracer: pushad
591 pushfd
592 mov bp,sp
593 mov bx,[bp+9*4]
594 mov al,[cs:bx]
595 inc word [bp+9*4]
596 mov ah,0Eh
597 mov bx,7
598 int 10h
599 popfd
600 popad
601 ret
602 %endif
603
604 section .data
605 alignb 2
606 00000000 [BC00] Int13Funcs dw Reset ; 00h - RESET
607 00000002 [0501] dw GetStatus ; 01h - GET STATUS
608 00000004 [1001] dw Read ; 02h - READ
609 00000006 [1B01] dw Write ; 03h - WRITE
610 00000008 [2D01] dw Verify ; 04h - VERIFY
611 0000000A [E000] dw Invalid ; 05h - FORMAT TRACK
612 0000000C [E000] dw Invalid ; 06h - FORMAT TRACK AND SET BAD FLAGS
613 0000000E [E000] dw Invalid ; 07h - FORMAT DRIVE AT TRACK
614 00000010 [3301] dw GetParms ; 08h - GET PARAMETERS
615 00000012 [3001] dw InitWithParms ; 09h - INITIALIZE CONTROLLER WITH DRIVE PARAMETERS
616 00000014 [E000] dw Invalid ; 0Ah
617 00000016 [E000] dw Invalid ; 0Bh
618 00000018 [2D01] dw Seek ; 0Ch - SEEK TO CYLINDER
619 0000001A [BC00] dw Reset ; 0Dh - RESET HARD DISKS
620 0000001C [E000] dw Invalid ; 0Eh
621 0000001E [E000] dw Invalid ; 0Fh
622 00000020 [3001] dw CheckIfReady ; 10h - CHECK IF READY
623 00000022 [3001] dw Recalibrate ; 11h - RECALIBRATE
624 00000024 [E000] dw Invalid ; 12h
625 00000026 [E000] dw Invalid ; 13h
626 00000028 [E000] dw Invalid ; 14h
627 0000002A [E500] dw GetDriveType ; 15h - GET DRIVE TYPE
628 0000002C [3001] dw DetectChange ; 16h - DETECT DRIVE CHANGE
629 %if 0
630 dw Invalid ; 17h
631 dw Invalid ; 18h
632 dw Invalid ; 19h
633 dw Invalid ; 1Ah
634 dw Invalid ; 1Bh
635 dw Invalid ; 1Ch
636 dw Invalid ; 1Dh
637 dw Invalid ; 1Eh
638 dw Invalid ; 1Fh
639 dw Invalid ; 20h
640 dw ReadMult ; 21h - READ MULTIPLE
641 dw WriteMult ; 22h - WRITE MULTIPLE
642 dw SetMode ; 23h - SET CONTROLLER FEATURES
643 dw SetMode ; 24h - SET MULTIPLE MODE
644 dw Invalid ; 25h - IDENTIFY DRIVE
645 dw Invalid ; 26h
646 dw Invalid ; 27h
647 dw Invalid ; 28h
648 dw Invalid ; 29h
649 dw Invalid ; 2Ah
650 dw Invalid ; 2Bh
651 dw Invalid ; 2Ch
652 dw Invalid ; 2Dh
653 dw Invalid ; 2Eh
654 dw Invalid ; 2Fh
655 dw Invalid ; 30h
656 dw Invalid ; 31h
657 dw Invalid ; 32h
658 dw Invalid ; 33h
659 dw Invalid ; 34h
660 dw Invalid ; 35h
661 dw Invalid ; 36h
662 dw Invalid ; 37h
663 dw Invalid ; 38h
664 dw Invalid ; 39h
665 dw Invalid ; 3Ah
666 dw Invalid ; 3Bh
667 dw Invalid ; 3Ch
668 dw Invalid ; 3Dh
669 dw Invalid ; 3Eh
670 dw Invalid ; 3Fh
671 dw Invalid ; 40h
672 dw EDDPresence ; 41h - EDD PRESENCE DETECT
673 dw EDDRead ; 42h - EDD READ
674 dw EDDWrite ; 43h - EDD WRITE
675 dw EDDVerify ; 44h - EDD VERIFY
676 dw Invalid ; 45h - EDD LOCK/UNLOCK MEDIA
677 dw Invalid ; 46h - EDD EJECT
678 dw EDDSeek ; 47h - EDD SEEK
679 dw EDDGetParms ; 48h - EDD GET PARAMETERS
680 %endif
681
682 Int13FuncsEnd equ $
683 Int13FuncsMax equ (Int13FuncsEnd-Int13Funcs) >> 1
684
685 0000002E 00<rept> alignb 8, db 0
686 00000030 1800 Shaker dw ShakerEnd-$
687 00000032 00000000 dd 0 ; Pointer to self
688 00000036 0000 dw 0
689
690 00000038 FFFF0000 Shaker_RMDS: dd 0x0000ffff ; 64K data segment
691 0000003C 00930000 dd 0x00009300
692
693 00000040 FFFF0000 Shaker_DS: dd 0x0000ffff ; 4GB data segment
694 00000044 00938F00 dd 0x008f9300
695
696 ShakerEnd equ $
697
698 alignb 8, db 0
699
700
701 00000048 000000000000000000- Mover dd 0, 0, 0, 0 ; Must be zero
702 00000051 00000000000000
703 00000058 FFFF dw 0ffffh ; 64 K segment size
704 0000005A 000000 Mover_src1: db 0, 0, 0 ; Low 24 bits of source addy
705 0000005D 93 db 93h ; Access rights
706 0000005E 00 db 00h ; Extended access rights
707 0000005F 00 Mover_src2: db 0 ; High 8 bits of source addy
708 00000060 FFFF dw 0ffffh ; 64 K segment size
709 00000062 000000 Mover_dst1: db 0, 0, 0 ; Low 24 bits of target addy
710 00000065 93 db 93h ; Access rights
711 00000066 00 db 00h ; Extended access rights
712 00000067 00 Mover_dst2: db 0 ; High 8 bits of source addy
713 00000068 000000000000000000- Mover_dummy2: dd 0, 0, 0, 0 ; More space for the BIOS
714 00000071 00000000000000
715
716 alignb 4, db 0
717 MemDisk_Info equ $ ; Pointed to by installation check
718 00000078 1B00 MDI_Bytes dw 27 ; Total bytes in MDI structure
719 0000007A 0903 MDI_Version db VER_MINOR, VER_MAJOR ; MEMDISK version
720
721 PatchArea equ $ ; This gets filled in by the installer
722
723 0000007C 00000000 DiskBuf dd 0 ; Linear address of high memory disk
724 00000080 00000000 DiskSize dd 0 ; Size of disk in blocks
725 00000084 00000000 CommandLine dw 0, 0 ; Far pointer to saved command line
726
727 00000088 00000000 OldInt13 dd 0 ; INT 13h in chain
728 0000008C 00000000 OldInt15 dd 0 ; INT 15h in chain
729
730 00000090 0000 OldDosMem dw 0 ; Old position of DOS mem end
731 00000092 00 BootLoaderID db 0 ; Boot loader ID from header
732 ; ---- MDI structure ends here ---
733 00000093 000000 db 0, 0, 0 ; pad
734
735 00000096 0000 MemInt1588 dw 0 ; 1MB-65MB memory amount (1K)
736
737 00000098 0000 Cylinders dw 0 ; Cylinder count
738 0000009A 0000 Heads dw 0 ; Head count
739 0000009C 00000000 Sectors dd 0 ; Sector count (zero-extended)
740
741 000000A0 00000000 Mem1MB dd 0 ; 1MB-16MB memory amount (1K)
742 000000A4 00000000 Mem16MB dd 0 ; 16MB-4G memory amount (64K)
743
744 000000A8 00 DriveNo db 0 ; Our drive number
745 000000A9 00 DriveType db 0 ; Our drive type (floppies)
746 000000AA 00 DriveCnt db 0 ; Drive count (from the BIOS)
747
748 000000AB 00 ConfigFlags db 0 ; Bit 0 - readonly
749
750 000000AC 0000 MyStack dw 0 ; Offset of stack
751 000000AE 0000 StatusPtr dw 0 ; Where to save status (zeroseg ptr)
752
753 000000B0 00<rept> DPT times 16 db 0 ; BIOS parameter table pointer (floppies)
754
755 ; End patch area
756
757 000000C0 00000000 Stack dd 0 ; Saved SS:ESP on invocation
758 000000C4 0000 dw 0
759 000000C6 0000 SavedAX dw 0 ; AX saved on invocation
760
761 alignb 4, db 0 ; We *MUST* end on a dword boundary
762
763 E820Table equ $ ; The installer loads the E820 table here
764 TotalSize equ $ ; End pointer

Binary file not shown.

View File

@@ -0,0 +1,768 @@
;; -*- fundamental -*-
;; $Id: memdisk16.asm,v 1.3 2004/12/14 22:46:25 hpa Exp $
;; -----------------------------------------------------------------------
;;
;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
;; Boston MA 02111-1307, USA; either version 2 of the License, or
;; (at your option) any later version; incorporated herein by reference.
;;
;; -----------------------------------------------------------------------
;;
;; init16.asm
;;
;; Routine to initialize and to trampoline into 32-bit
;; protected memory. This code is derived from bcopy32.inc and
;; com32.inc in the main SYSLINUX distribution.
;;
MY_CS equ 0x0800 ; Segment address to use
CS_BASE equ (MY_CS << 4) ; Corresponding address
; Low memory bounce buffer
BOUNCE_SEG equ (MY_CS+0x1000)
%define DO_WBINVD 0
%define STACK_HEAP_SIZE (128*1024)
section .rodata align=16
section .data align=16
section .bss align=16
;; -----------------------------------------------------------------------
;; Kernel image header
;; -----------------------------------------------------------------------
section .text ; Must be first in image
bits 16
cmdline times 497 db 0 ; We put the command line here
setup_sects db 0
root_flags dw 0
syssize dw 0
swap_dev dw 0
ram_size dw 0
vid_mode dw 0
root_dev dw 0
boot_flag dw 0xAA55
_start: jmp short start
db "HdrS" ; Header signature
dw 0x0203 ; Header version number
realmode_swtch dw 0, 0 ; default_switch, SETUPSEG
start_sys_seg dw 0x1000 ; obsolete
version_ptr dw memdisk_version-0x200 ; version string ptr
type_of_loader db 0 ; Filled in by boot loader
loadflags db 1 ; Please load high
setup_move_size dw 0 ; Unused
code32_start dd 0x100000 ; 32-bit start address
ramdisk_image dd 0 ; Loaded ramdisk image address
ramdisk_size dd 0 ; Size of loaded ramdisk
bootsect_kludge dw 0, 0
heap_end_ptr dw 0
pad1 dw 0
cmd_line_ptr dd 0 ; Command line
ramdisk_max dd 0xffffffff ; Highest allowed ramdisk address
section .rodata
memdisk_version:
db "MEMDISK ", VERSION, " ", DATE, 0
;; -----------------------------------------------------------------------
;; End kernel image header
;; -----------------------------------------------------------------------
;
; Move ourselves down into memory to reduce the risk of conflicts;
; then canonicalize CS to match the other segments.
;
section .text
bits 16
start:
mov ax,MY_CS
mov es,ax
movzx cx,byte [setup_sects]
inc cx ; Add one for the boot sector
shl cx,7 ; Convert to dwords
xor si,si
xor di,di
mov fs,si ; fs <- 0
cld
rep movsd
mov ds,ax
mov ss,ax
xor esp,esp ; Stack at top of 64K segment
jmp MY_CS:.next
.next:
;
; Copy the command line, if there is one
;
copy_cmdline:
xor di,di ; Bottom of our own segment (= "boot sector")
mov eax,[cmd_line_ptr]
and eax,eax
jz .endcmd ; No command line
mov si,ax
shr eax,4 ; Convert to segment
and si,0x000F ; Starting offset only
mov gs,ax
mov cx,496 ; Max number of bytes
.copycmd:
gs lodsb
and al,al
jz .endcmd
stosb
loop .copycmd
.endcmd:
xor al,al
stosb
;
; Now jump to 32-bit code
;
sti
call init32
;
; When init32 returns, we have been set up, the new boot sector loaded,
; and we should go and and run the newly loaded boot sector
;
; The setup function returns (in AL) the drive number which should be
; put into DL
;
mov dx,ax
cli
xor esi,esi ; No partition table involved
mov ds,si ; Make all the segments consistent
mov es,si
mov fs,si
mov gs,si
mov ss,si
mov esp,0x7C00 ; Good place for SP to start out
jmp 0:0x7C00
;
; We enter protected mode, set up a flat 32-bit environment, run rep movsd
; and then exit. IMPORTANT: This code assumes cs == MY_CS.
;
; This code is probably excessively anal-retentive in its handling of
; segments, but this stuff is painful enough as it is without having to rely
; on everything happening "as it ought to."
;
section .rodata
; desc base, limit, flags
%macro desc 3
dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
%endmacro
align 8, db 0
call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT
.adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction
dw 0
; 0008: Code segment, use16, readable, dpl 0, base CS_BASE, 64K
desc CS_BASE, 0xffff, 0x009b
; 0010: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K
desc CS_BASE, 0xffff, 0x0093
; 0018: Data segment, use16, read/write, dpl 0, base 0, 4G
desc 0, 0xfffff, 0x809b
; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G
desc 0, 0xfffff, 0xc09b
; 0028: Data segment, use32, read/write, dpl 0, base 0, 4G
desc 0, 0xfffff, 0xc093
call32_gdt_size: equ $-call32_gdt
err_a20: db 'ERROR: A20 gate not responding!',13,10,0
section .bss
alignb 4
SavedSSSP resd 1 ; Place to save SS:SP
Return resd 1 ; Return value
A20Test resw 1 ; Space to test A20
A20Tries resb 1
section .data
alignb 4
Target dd 0 ; Target address
Target_Seg dw 20h ; Target CS
A20Type dw 0 ; Default = unknown
section .text
bits 16
;
; Routines to enable and disable (yuck) A20. These routines are gathered
; from tips from a couple of sources, including the Linux kernel and
; http://www.x86.org/. The need for the delay to be as large as given here
; is indicated by Donnie Barnes of RedHat, the problematic system being an
; IBM ThinkPad 760EL.
;
; We typically toggle A20 twice for every 64K transferred.
;
%define io_delay call _io_delay
%define IO_DELAY_PORT 80h ; Invalid port (we hope!)
%define disable_wait 32 ; How long to wait for a disable
%define A20_DUNNO 0 ; A20 type unknown
%define A20_NONE 1 ; A20 always on?
%define A20_BIOS 2 ; A20 BIOS enable
%define A20_KBC 3 ; A20 through KBC
%define A20_FAST 4 ; A20 through port 92h
align 2, db 0
A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
a20_adjust_cnt equ ($-A20List)/2
slow_out: out dx, al ; Fall through
_io_delay: out IO_DELAY_PORT,al
out IO_DELAY_PORT,al
ret
enable_a20:
pushad
mov byte [A20Tries],255 ; Times to try to make this work
try_enable_a20:
;
; Flush the caches
;
%if DO_WBINVD
call try_wbinvd
%endif
;
; If the A20 type is known, jump straight to type
;
mov bp,[A20Type]
add bp,bp ; Convert to word offset
.adj4: jmp word [bp+A20List]
;
; First, see if we are on a system with no A20 gate
;
a20_dunno:
a20_none:
mov byte [A20Type], A20_NONE
call a20_test
jnz a20_done
;
; Next, try the BIOS (INT 15h AX=2401h)
;
a20_bios:
mov byte [A20Type], A20_BIOS
mov ax,2401h
pushf ; Some BIOSes muck with IF
int 15h
popf
call a20_test
jnz a20_done
;
; Enable the keyboard controller A20 gate
;
a20_kbc:
mov dl, 1 ; Allow early exit
call empty_8042
jnz a20_done ; A20 live, no need to use KBC
mov byte [A20Type], A20_KBC ; Starting KBC command sequence
mov al,0D1h ; Command write
out 064h, al
call empty_8042_uncond
mov al,0DFh ; A20 on
out 060h, al
call empty_8042_uncond
; Verify that A20 actually is enabled. Do that by
; observing a word in low memory and the same word in
; the HMA until they are no longer coherent. Note that
; we don't do the same check in the disable case, because
; we don't want to *require* A20 masking (SYSLINUX should
; work fine without it, if the BIOS does.)
.kbc_wait: push cx
xor cx,cx
.kbc_wait_loop:
call a20_test
jnz a20_done_pop
loop .kbc_wait_loop
pop cx
;
; Running out of options here. Final attempt: enable the "fast A20 gate"
;
a20_fast:
mov byte [A20Type], A20_FAST ; Haven't used the KBC yet
in al, 092h
or al,02h
and al,~01h ; Don't accidentally reset the machine!
out 092h, al
.fast_wait: push cx
xor cx,cx
.fast_wait_loop:
call a20_test
jnz a20_done_pop
loop .fast_wait_loop
pop cx
;
; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
; and report failure to the user.
;
dec byte [A20Tries]
jnz try_enable_a20
; Error message time
mov si,err_a20
print_err:
lodsb
and al,al
jz die
mov bx,7
mov ah,0xe
int 10h
jmp print_err
die:
sti
.hlt: hlt
jmp short .hlt
;
; A20 unmasked, proceed...
;
a20_done_pop: pop cx
a20_done: popad
ret
;
; This routine tests if A20 is enabled (ZF = 0). This routine
; must not destroy any register contents.
;
a20_test:
push es
push cx
push ax
mov cx,0FFFFh ; HMA = segment 0FFFFh
mov es,cx
mov cx,32 ; Loop count
mov ax,[A20Test]
.a20_wait: inc ax
mov [A20Test],ax
io_delay ; Serialize, and fix delay
cmp ax,[es:A20Test+CS_BASE+10h]
loopz .a20_wait
.a20_done: pop ax
pop cx
pop es
ret
disable_a20:
pushad
;
; Flush the caches
;
%if DO_WBINVD
call try_wbinvd
%endif
mov bp,[A20Type]
add bp,bp ; Convert to word offset
.adj5: jmp word [bp+A20DList]
a20d_bios:
mov ax,2400h
pushf ; Some BIOSes muck with IF
int 15h
popf
jmp short a20d_snooze
;
; Disable the "fast A20 gate"
;
a20d_fast:
in al, 092h
and al,~03h
out 092h, al
jmp short a20d_snooze
;
; Disable the keyboard controller A20 gate
;
a20d_kbc:
call empty_8042_uncond
mov al,0D1h
out 064h, al ; Command write
call empty_8042_uncond
mov al,0DDh ; A20 off
out 060h, al
call empty_8042_uncond
; Wait a bit for it to take effect
a20d_snooze:
push cx
mov cx, disable_wait
.delayloop: call a20_test
jz .disabled
loop .delayloop
.disabled: pop cx
a20d_dunno:
a20d_none:
popad
ret
;
; Routine to empty the 8042 KBC controller. If dl != 0
; then we will test A20 in the loop and exit if A20 is
; suddenly enabled.
;
empty_8042_uncond:
xor dl,dl
empty_8042:
call a20_test
jz .a20_on
and dl,dl
jnz .done
.a20_on: io_delay
in al, 064h ; Status port
test al,1
jz .no_output
io_delay
in al, 060h ; Read input
jmp short empty_8042
.no_output:
test al,2
jnz empty_8042
io_delay
.done: ret
;
; Execute a WBINVD instruction if possible on this CPU
;
%if DO_WBINVD
try_wbinvd:
wbinvd
ret
%endif
section .bss
alignb 4
PMESP resd 1 ; Protected mode %esp
section .idt nobits align=4096
alignb 4096
pm_idt resb 4096 ; Protected-mode IDT, followed by interrupt stubs
pm_entry: equ 0x100000
section .rodata
align 4, db 0
call32_pmidt:
dw 8*256 ; Limit
dd pm_idt+CS_BASE ; Address
call32_rmidt:
dw 0ffffh ; Limit
dd 0 ; Address
section .text
;
; This is the main entrypoint in this function
;
init32:
mov ebx,call32_call_start+CS_BASE ; Where to go in PM
call32_enter_pm:
mov ax,cs
mov ds,ax
cli
mov [SavedSSSP],sp
mov [SavedSSSP+2],ss
cld
call a20_test
jnz .a20ok
call enable_a20
.a20ok:
lgdt [call32_gdt] ; Set up GDT
lidt [call32_pmidt] ; Set up the IDT
mov eax,cr0
or al,1
mov cr0,eax ; Enter protected mode
jmp 20h:dword .in_pm+CS_BASE
bits 32
.in_pm:
xor eax,eax ; Available for future use...
mov fs,eax
mov gs,eax
mov al,28h ; Set up data segments
mov es,eax
mov ds,eax
mov ss,eax
mov esp,[PMESP+CS_BASE] ; Load protmode %esp if available
jmp ebx ; Go to where we need to go
;
; This is invoked before first dispatch of the 32-bit code, in 32-bit mode
;
call32_call_start:
;
; Point the stack into low memory
; We have: this segment, bounce buffer, then stack+heap
;
mov esp, CS_BASE + 0x20000 + STACK_HEAP_SIZE
and esp, ~0xf
;
; Set up the protmode IDT and the interrupt jump buffers
;
mov edi,pm_idt+CS_BASE
; Form an interrupt gate descriptor
; WARNING: This is broken if pm_idt crosses a 64K boundary;
; however, it can't because of the alignment constraints.
mov ebx,pm_idt+CS_BASE+8*256
mov eax,0x0020ee00
xchg ax,bx
xor ecx,ecx
inc ch ; ecx <- 256
push ecx
.make_idt:
stosd
add eax,8
xchg eax,ebx
stosd
xchg eax,ebx
loop .make_idt
pop ecx
; Each entry in the interrupt jump buffer contains
; the following instructions:
;
; 00000000 60 pushad
; 00000001 B0xx mov al,<interrupt#>
; 00000003 E9xxxxxxxx jmp call32_handle_interrupt
mov eax,0xe900b060
mov ebx,call32_handle_interrupt+CS_BASE
sub ebx,edi
.make_ijb:
stosd
sub [edi-2],cl ; Interrupt #
xchg eax,ebx
sub eax,8
stosd
xchg eax,ebx
loop .make_ijb
; Now everything is set up for interrupts...
push dword (BOUNCE_SEG << 4) ; Bounce buffer address
push dword call32_syscall+CS_BASE ; Syscall entry point
sti ; Interrupts OK now
call pm_entry-CS_BASE ; Run the program...
; ... on return ...
mov [Return+CS_BASE],eax
; ... fall through to call32_exit ...
call32_exit:
mov bx,call32_done ; Return to command loop
call32_enter_rm:
cli
cld
mov [PMESP+CS_BASE],esp ; Save exit %esp
xor esp,esp ; Make sure the high bits are zero
jmp 08h:.in_pm16 ; Return to 16-bit mode first
bits 16
.in_pm16:
mov ax,10h ; Real-mode-like segment
mov es,ax
mov ds,ax
mov ss,ax
mov fs,ax
mov gs,ax
lidt [call32_rmidt] ; Real-mode IDT (rm needs no GDT)
mov eax,cr0
and al,~1
mov cr0,eax
jmp MY_CS:.in_rm
.in_rm: ; Back in real mode
mov ax,cs ; Set up sane segments
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
lss sp,[SavedSSSP] ; Restore stack
jmp bx ; Go to whereever we need to go...
call32_done:
call disable_a20
sti
mov ax,[Return]
ret
;
; 16-bit support code
;
bits 16
;
; 16-bit interrupt-handling code
;
call32_int_rm:
pushf ; Flags on stack
push cs ; Return segment
push word .cont ; Return address
push dword edx ; Segment:offset of IVT entry
retf ; Invoke IVT routine
.cont: ; ... on resume ...
mov ebx,call32_int_resume+CS_BASE
jmp call32_enter_pm ; Go back to PM
;
; 16-bit system call handling code
;
call32_sys_rm:
pop gs
pop fs
pop es
pop ds
popad
popfd
retf ; Invoke routine
.return:
pushfd
pushad
push ds
push es
push fs
push gs
mov ebx,call32_sys_resume+CS_BASE
jmp call32_enter_pm
;
; 32-bit support code
;
bits 32
;
; This is invoked on getting an interrupt in protected mode. At
; this point, we need to context-switch to real mode and invoke
; the interrupt routine.
;
; When this gets invoked, the registers are saved on the stack and
; AL contains the register number.
;
call32_handle_interrupt:
movzx eax,al
xor ebx,ebx ; Actually makes the code smaller
mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
mov bx,call32_int_rm
jmp call32_enter_rm ; Go to real mode
call32_int_resume:
popad
iret
;
; Syscall invocation. We manifest a structure on the real-mode stack,
; containing the call32sys_t structure from <call32.h> as well as
; the following entries (from low to high address):
; - Target offset
; - Target segment
; - Return offset
; - Return segment (== real mode cs)
; - Return flags
;
call32_syscall:
pushfd ; Save IF among other things...
pushad ; We only need to save some, but...
cld
movzx edi,word [SavedSSSP+CS_BASE]
movzx eax,word [SavedSSSP+CS_BASE+2]
sub edi,54 ; Allocate 54 bytes
mov [SavedSSSP+CS_BASE],di
shl eax,4
add edi,eax ; Create linear address
mov esi,[esp+11*4] ; Source regs
xor ecx,ecx
mov cl,11 ; 44 bytes to copy
rep movsd
movzx eax,byte [esp+10*4] ; Interrupt number
; ecx == 0 here; adding it to the EA makes the
; encoding smaller
mov eax,[ecx+eax*4] ; Get IVT entry
stosd ; Save in stack frame
mov eax,call32_sys_rm.return + (MY_CS << 16) ; Return seg:offs
stosd ; Save in stack frame
mov eax,[edi-12] ; Return flags
and eax,0x200cd7 ; Mask (potentially) unsafe flags
mov [edi-12],eax ; Primary flags entry
stosw ; Return flags
mov bx,call32_sys_rm
jmp call32_enter_rm ; Go to real mode
; On return, the 44-byte return structure is on the
; real-mode stack.
call32_sys_resume:
movzx esi,word [SavedSSSP+CS_BASE]
movzx eax,word [SavedSSSP+CS_BASE+2]
mov edi,[esp+12*4] ; Dest regs
shl eax,4
add esi,eax ; Create linear address
and edi,edi ; NULL pointer?
jnz .do_copy
.no_copy: mov edi,esi ; Do a dummy copy-to-self
.do_copy: xor ecx,ecx
mov cl,11 ; 44 bytes
rep movsd ; Copy register block
add dword [SavedSSSP+CS_BASE],44 ; Remove from stack
popad
popfd
ret ; Return to 32-bit program

Binary file not shown.

View File

@@ -0,0 +1,785 @@
1 ;; -*- fundamental -*-
2 ;; $Id: memdisk16.asm,v 1.3 2004/12/14 22:46:25 hpa Exp $
3 ;; -----------------------------------------------------------------------
4 ;;
5 ;; Copyright 1994-2004 H. Peter Anvin - All Rights Reserved
6 ;;
7 ;; This program is free software; you can redistribute it and/or modify
8 ;; it under the terms of the GNU General Public License as published by
9 ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
10 ;; Boston MA 02111-1307, USA; either version 2 of the License, or
11 ;; (at your option) any later version; incorporated herein by reference.
12 ;;
13 ;; -----------------------------------------------------------------------
14
15 ;;
16 ;; init16.asm
17 ;;
18 ;; Routine to initialize and to trampoline into 32-bit
19 ;; protected memory. This code is derived from bcopy32.inc and
20 ;; com32.inc in the main SYSLINUX distribution.
21 ;;
22
23 MY_CS equ 0x0800 ; Segment address to use
24 CS_BASE equ (MY_CS << 4) ; Corresponding address
25
26 ; Low memory bounce buffer
27 BOUNCE_SEG equ (MY_CS+0x1000)
28
29 %define DO_WBINVD 0
30
31 %define STACK_HEAP_SIZE (128*1024)
32
33 section .rodata align=16
34 section .data align=16
35 section .bss align=16
36
37 ;; -----------------------------------------------------------------------
38 ;; Kernel image header
39 ;; -----------------------------------------------------------------------
40
41 section .text ; Must be first in image
42 bits 16
43
44 00000000 00<rept> cmdline times 497 db 0 ; We put the command line here
45 000001F1 00 setup_sects db 0
46 000001F2 0000 root_flags dw 0
47 000001F4 0000 syssize dw 0
48 000001F6 0000 swap_dev dw 0
49 000001F8 0000 ram_size dw 0
50 000001FA 0000 vid_mode dw 0
51 000001FC 0000 root_dev dw 0
52 000001FE 55AA boot_flag dw 0xAA55
53
54 00000200 EB2E _start: jmp short start
55
56 00000202 48647253 db "HdrS" ; Header signature
57 00000206 0302 dw 0x0203 ; Header version number
58
59 00000208 00000000 realmode_swtch dw 0, 0 ; default_switch, SETUPSEG
60 0000020C 0010 start_sys_seg dw 0x1000 ; obsolete
61 0000020E [00FE] version_ptr dw memdisk_version-0x200 ; version string ptr
62 00000210 00 type_of_loader db 0 ; Filled in by boot loader
63 00000211 01 loadflags db 1 ; Please load high
64 00000212 0000 setup_move_size dw 0 ; Unused
65 00000214 00001000 code32_start dd 0x100000 ; 32-bit start address
66 00000218 00000000 ramdisk_image dd 0 ; Loaded ramdisk image address
67 0000021C 00000000 ramdisk_size dd 0 ; Size of loaded ramdisk
68 00000220 00000000 bootsect_kludge dw 0, 0
69 00000224 0000 heap_end_ptr dw 0
70 00000226 0000 pad1 dw 0
71 00000228 00000000 cmd_line_ptr dd 0 ; Command line
72 0000022C FFFFFFFF ramdisk_max dd 0xffffffff ; Highest allowed ramdisk address
73
74 section .rodata
75 memdisk_version:
76 00000000 4D454D4449534B2033- db "MEMDISK ", VERSION, " ", DATE, 0
77 00000009 2E3039203078343165-
78 00000012 666662636100
79
80 ;; -----------------------------------------------------------------------
81 ;; End kernel image header
82 ;; -----------------------------------------------------------------------
83
84 ;
85 ; Move ourselves down into memory to reduce the risk of conflicts;
86 ; then canonicalize CS to match the other segments.
87 ;
88 section .text
89 bits 16
90 start:
91 00000230 B80008 mov ax,MY_CS
92 00000233 8EC0 mov es,ax
93 00000235 0FB60E[F101] movzx cx,byte [setup_sects]
94 0000023A 41 inc cx ; Add one for the boot sector
95 0000023B C1E107 shl cx,7 ; Convert to dwords
96 0000023E 31F6 xor si,si
97 00000240 31FF xor di,di
98 00000242 8EE6 mov fs,si ; fs <- 0
99 00000244 FC cld
100 00000245 F366A5 rep movsd
101 00000248 8ED8 mov ds,ax
102 0000024A 8ED0 mov ss,ax
103 0000024C 6631E4 xor esp,esp ; Stack at top of 64K segment
104 0000024F EA[5402]0008 jmp MY_CS:.next
105 .next:
106
107 ;
108 ; Copy the command line, if there is one
109 ;
110 copy_cmdline:
111 00000254 31FF xor di,di ; Bottom of our own segment (= "boot sector")
112 00000256 66A1[2802] mov eax,[cmd_line_ptr]
113 0000025A 6621C0 and eax,eax
114 0000025D 7417 jz .endcmd ; No command line
115 0000025F 89C6 mov si,ax
116 00000261 66C1E804 shr eax,4 ; Convert to segment
117 00000265 83E60F and si,0x000F ; Starting offset only
118 00000268 8EE8 mov gs,ax
119 0000026A B9F001 mov cx,496 ; Max number of bytes
120 .copycmd:
121 0000026D 65AC gs lodsb
122 0000026F 20C0 and al,al
123 00000271 7403 jz .endcmd
124 00000273 AA stosb
125 00000274 E2F7 loop .copycmd
126 .endcmd:
127 00000276 30C0 xor al,al
128 00000278 AA stosb
129
130 ;
131 ; Now jump to 32-bit code
132 ;
133 00000279 FB sti
134 0000027A E83D01 call init32
135 ;
136 ; When init32 returns, we have been set up, the new boot sector loaded,
137 ; and we should go and and run the newly loaded boot sector
138 ;
139 ; The setup function returns (in AL) the drive number which should be
140 ; put into DL
141 ;
142 0000027D 89C2 mov dx,ax
143
144 0000027F FA cli
145 00000280 6631F6 xor esi,esi ; No partition table involved
146 00000283 8EDE mov ds,si ; Make all the segments consistent
147 00000285 8EC6 mov es,si
148 00000287 8EE6 mov fs,si
149 00000289 8EEE mov gs,si
150 0000028B 8ED6 mov ss,si
151 0000028D 66BC007C0000 mov esp,0x7C00 ; Good place for SP to start out
152 00000293 EA007C0000 jmp 0:0x7C00
153
154 ;
155 ; We enter protected mode, set up a flat 32-bit environment, run rep movsd
156 ; and then exit. IMPORTANT: This code assumes cs == MY_CS.
157 ;
158 ; This code is probably excessively anal-retentive in its handling of
159 ; segments, but this stuff is painful enough as it is without having to rely
160 ; on everything happening "as it ought to."
161 ;
162 section .rodata
163
164 ; desc base, limit, flags
165 %macro desc 3
166 dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
167 dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
168 %endmacro
169
170 align 8, db 0
171 00000018 2F00 call32_gdt: dw call32_gdt_size-1 ; Null descriptor - contains GDT
172 0000001A [18800000] .adj1: dd call32_gdt+CS_BASE ; pointer for LGDT instruction
173 0000001E 0000 dw 0
174
175 ; 0008: Code segment, use16, readable, dpl 0, base CS_BASE, 64K
176 desc CS_BASE, 0xffff, 0x009b
177 00000020 FFFF0080 <1> dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
178 00000024 009B0000 <1> dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
179
180 ; 0010: Data segment, use16, read/write, dpl 0, base CS_BASE, 64K
181 desc CS_BASE, 0xffff, 0x0093
182 00000028 FFFF0080 <1> dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
183 0000002C 00930000 <1> dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
184
185 ; 0018: Data segment, use16, read/write, dpl 0, base 0, 4G
186 desc 0, 0xfffff, 0x809b
187 00000030 FFFF0000 <1> dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
188 00000034 009B8F00 <1> dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
189
190 ; 0020: Code segment, use32, read/write, dpl 0, base 0, 4G
191 desc 0, 0xfffff, 0xc09b
192 00000038 FFFF0000 <1> dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
193 0000003C 009BCF00 <1> dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
194
195 ; 0028: Data segment, use32, read/write, dpl 0, base 0, 4G
196 desc 0, 0xfffff, 0xc093
197 00000040 FFFF0000 <1> dd (%2 & 0xffff) | ((%1 & 0xffff) << 16)
198 00000044 0093CF00 <1> dd (%1 & 0xff000000) | (%2 & 0xf0000) | ((%3 & 0xf0ff) << 8) | ((%1 & 0x00ff0000) >> 16)
199
200 call32_gdt_size: equ $-call32_gdt
201
202 00000048 4552524F523A204132- err_a20: db 'ERROR: A20 gate not responding!',13,10,0
203 00000051 302067617465206E6F-
204 0000005A 7420726573706F6E64-
205 00000063 696E67210D0A00
206
207 section .bss
208 alignb 4
209 00000000 <res 00000004> SavedSSSP resd 1 ; Place to save SS:SP
210 00000004 <res 00000004> Return resd 1 ; Return value
211 00000008 <res 00000002> A20Test resw 1 ; Space to test A20
212 0000000A <res 00000001> A20Tries resb 1
213
214 section .data
215 alignb 4
216 00000000 00000000 Target dd 0 ; Target address
217 00000004 2000 Target_Seg dw 20h ; Target CS
218
219 00000006 0000 A20Type dw 0 ; Default = unknown
220
221 section .text
222 bits 16
223 ;
224 ; Routines to enable and disable (yuck) A20. These routines are gathered
225 ; from tips from a couple of sources, including the Linux kernel and
226 ; http://www.x86.org/. The need for the delay to be as large as given here
227 ; is indicated by Donnie Barnes of RedHat, the problematic system being an
228 ; IBM ThinkPad 760EL.
229 ;
230 ; We typically toggle A20 twice for every 64K transferred.
231 ;
232 %define io_delay call _io_delay
233 %define IO_DELAY_PORT 80h ; Invalid port (we hope!)
234 %define disable_wait 32 ; How long to wait for a disable
235
236 %define A20_DUNNO 0 ; A20 type unknown
237 %define A20_NONE 1 ; A20 always on?
238 %define A20_BIOS 2 ; A20 BIOS enable
239 %define A20_KBC 3 ; A20 through KBC
240 %define A20_FAST 4 ; A20 through port 92h
241
242 align 2, db 0
243 00000298 [C302][C302][CD02]- A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast
244 0000029E [DE02][0303]
245 000002A2 [9403][9403][6603]- A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast
246 000002A8 [7703][6F03]
247 a20_adjust_cnt equ ($-A20List)/2
248
249 000002AC EE slow_out: out dx, al ; Fall through
250
251 000002AD E680 _io_delay: out IO_DELAY_PORT,al
252 000002AF E680 out IO_DELAY_PORT,al
253 000002B1 C3 ret
254
255 enable_a20:
256 000002B2 6660 pushad
257 000002B4 C606[0A00]FF mov byte [A20Tries],255 ; Times to try to make this work
258
259 try_enable_a20:
260
261 ;
262 ; Flush the caches
263 ;
264 %if DO_WBINVD
265 call try_wbinvd
266 %endif
267
268 ;
269 ; If the A20 type is known, jump straight to type
270 ;
271 000002B9 8B2E[0600] mov bp,[A20Type]
272 000002BD 01ED add bp,bp ; Convert to word offset
273 000002BF FFA6[9802] .adj4: jmp word [bp+A20List]
274
275 ;
276 ; First, see if we are on a system with no A20 gate
277 ;
278 a20_dunno:
279 a20_none:
280 000002C3 C606[0600]01 mov byte [A20Type], A20_NONE
281 000002C8 E86F00 call a20_test
282 000002CB 756A jnz a20_done
283
284 ;
285 ; Next, try the BIOS (INT 15h AX=2401h)
286 ;
287 a20_bios:
288 000002CD C606[0600]02 mov byte [A20Type], A20_BIOS
289 000002D2 B80124 mov ax,2401h
290 000002D5 9C pushf ; Some BIOSes muck with IF
291 000002D6 CD15 int 15h
292 000002D8 9D popf
293
294 000002D9 E85E00 call a20_test
295 000002DC 7559 jnz a20_done
296
297 ;
298 ; Enable the keyboard controller A20 gate
299 ;
300 a20_kbc:
301 000002DE B201 mov dl, 1 ; Allow early exit
302 000002E0 E8B600 call empty_8042
303 000002E3 7552 jnz a20_done ; A20 live, no need to use KBC
304
305 000002E5 C606[0600]03 mov byte [A20Type], A20_KBC ; Starting KBC command sequence
306
307 000002EA B0D1 mov al,0D1h ; Command write
308 000002EC E664 out 064h, al
309 000002EE E8A600 call empty_8042_uncond
310
311 000002F1 B0DF mov al,0DFh ; A20 on
312 000002F3 E660 out 060h, al
313 000002F5 E89F00 call empty_8042_uncond
314
315 ; Verify that A20 actually is enabled. Do that by
316 ; observing a word in low memory and the same word in
317 ; the HMA until they are no longer coherent. Note that
318 ; we don't do the same check in the disable case, because
319 ; we don't want to *require* A20 masking (SYSLINUX should
320 ; work fine without it, if the BIOS does.)
321 000002F8 51 .kbc_wait: push cx
322 000002F9 31C9 xor cx,cx
323 .kbc_wait_loop:
324 000002FB E83C00 call a20_test
325 000002FE 7536 jnz a20_done_pop
326 00000300 E2F9 loop .kbc_wait_loop
327
328 00000302 59 pop cx
329 ;
330 ; Running out of options here. Final attempt: enable the "fast A20 gate"
331 ;
332 a20_fast:
333 00000303 C606[0600]04 mov byte [A20Type], A20_FAST ; Haven't used the KBC yet
334 00000308 E492 in al, 092h
335 0000030A 0C02 or al,02h
336 0000030C 24FE and al,~01h ; Don't accidentally reset the machine!
337 0000030E E692 out 092h, al
338
339 00000310 51 .fast_wait: push cx
340 00000311 31C9 xor cx,cx
341 .fast_wait_loop:
342 00000313 E82400 call a20_test
343 00000316 751E jnz a20_done_pop
344 00000318 E2F9 loop .fast_wait_loop
345
346 0000031A 59 pop cx
347
348 ;
349 ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
350 ; and report failure to the user.
351 ;
352
353 0000031B FE0E[0A00] dec byte [A20Tries]
354 0000031F 7598 jnz try_enable_a20
355
356
357 ; Error message time
358 00000321 BE[4800] mov si,err_a20
359 print_err:
360 00000324 AC lodsb
361 00000325 20C0 and al,al
362 00000327 7409 jz die
363 00000329 BB0700 mov bx,7
364 0000032C B40E mov ah,0xe
365 0000032E CD10 int 10h
366 00000330 EBF2 jmp print_err
367
368
369 die:
370 00000332 FB sti
371 00000333 F4 .hlt: hlt
372 00000334 EBFD jmp short .hlt
373
374 ;
375 ; A20 unmasked, proceed...
376 ;
377 00000336 59 a20_done_pop: pop cx
378 00000337 6661 a20_done: popad
379 00000339 C3 ret
380
381 ;
382 ; This routine tests if A20 is enabled (ZF = 0). This routine
383 ; must not destroy any register contents.
384 ;
385 a20_test:
386 0000033A 06 push es
387 0000033B 51 push cx
388 0000033C 50 push ax
389 0000033D B9FFFF mov cx,0FFFFh ; HMA = segment 0FFFFh
390 00000340 8EC1 mov es,cx
391 00000342 B92000 mov cx,32 ; Loop count
392 00000345 A1[0800] mov ax,[A20Test]
393 00000348 40 .a20_wait: inc ax
394 00000349 A3[0800] mov [A20Test],ax
395 0000034C E85EFF io_delay ; Serialize, and fix delay
396 0000034F 263B06[1880] cmp ax,[es:A20Test+CS_BASE+10h]
397 00000354 E1F2 loopz .a20_wait
398 00000356 58 .a20_done: pop ax
399 00000357 59 pop cx
400 00000358 07 pop es
401 00000359 C3 ret
402
403 disable_a20:
404 0000035A 6660 pushad
405 ;
406 ; Flush the caches
407 ;
408 %if DO_WBINVD
409 call try_wbinvd
410 %endif
411
412 0000035C 8B2E[0600] mov bp,[A20Type]
413 00000360 01ED add bp,bp ; Convert to word offset
414 00000362 FFA6[A202] .adj5: jmp word [bp+A20DList]
415
416 a20d_bios:
417 00000366 B80024 mov ax,2400h
418 00000369 9C pushf ; Some BIOSes muck with IF
419 0000036A CD15 int 15h
420 0000036C 9D popf
421 0000036D EB19 jmp short a20d_snooze
422
423 ;
424 ; Disable the "fast A20 gate"
425 ;
426 a20d_fast:
427 0000036F E492 in al, 092h
428 00000371 24FC and al,~03h
429 00000373 E692 out 092h, al
430 00000375 EB11 jmp short a20d_snooze
431
432 ;
433 ; Disable the keyboard controller A20 gate
434 ;
435 a20d_kbc:
436 00000377 E81D00 call empty_8042_uncond
437 0000037A B0D1 mov al,0D1h
438 0000037C E664 out 064h, al ; Command write
439 0000037E E81600 call empty_8042_uncond
440 00000381 B0DD mov al,0DDh ; A20 off
441 00000383 E660 out 060h, al
442 00000385 E80F00 call empty_8042_uncond
443 ; Wait a bit for it to take effect
444 a20d_snooze:
445 00000388 51 push cx
446 00000389 B92000 mov cx, disable_wait
447 0000038C E8ABFF .delayloop: call a20_test
448 0000038F 7402 jz .disabled
449 00000391 E2F9 loop .delayloop
450 00000393 59 .disabled: pop cx
451 a20d_dunno:
452 a20d_none:
453 00000394 6661 popad
454 00000396 C3 ret
455
456 ;
457 ; Routine to empty the 8042 KBC controller. If dl != 0
458 ; then we will test A20 in the loop and exit if A20 is
459 ; suddenly enabled.
460 ;
461 empty_8042_uncond:
462 00000397 30D2 xor dl,dl
463 empty_8042:
464 00000399 E89EFF call a20_test
465 0000039C 7404 jz .a20_on
466 0000039E 20D2 and dl,dl
467 000003A0 7517 jnz .done
468 000003A2 E808FF .a20_on: io_delay
469 000003A5 E464 in al, 064h ; Status port
470 000003A7 A801 test al,1
471 000003A9 7407 jz .no_output
472 000003AB E8FFFE io_delay
473 000003AE E460 in al, 060h ; Read input
474 000003B0 EBE7 jmp short empty_8042
475 .no_output:
476 000003B2 A802 test al,2
477 000003B4 75E3 jnz empty_8042
478 000003B6 E8F4FE io_delay
479 000003B9 C3 .done: ret
480
481 ;
482 ; Execute a WBINVD instruction if possible on this CPU
483 ;
484 %if DO_WBINVD
485 try_wbinvd:
486 wbinvd
487 ret
488 %endif
489
490 section .bss
491 0000000B <res 00000001> alignb 4
492 0000000C <res 00000004> PMESP resd 1 ; Protected mode %esp
493
494 section .idt nobits align=4096
495 alignb 4096
496 00000000 <res 00001000> pm_idt resb 4096 ; Protected-mode IDT, followed by interrupt stubs
497
498
499
500
501 pm_entry: equ 0x100000
502
503 section .rodata
504 0000006A 00<rept> align 4, db 0
505 call32_pmidt:
506 0000006C 0008 dw 8*256 ; Limit
507 0000006E [00800000] dd pm_idt+CS_BASE ; Address
508
509 call32_rmidt:
510 00000072 FFFF dw 0ffffh ; Limit
511 00000074 00000000 dd 0 ; Address
512
513 section .text
514 ;
515 ; This is the main entrypoint in this function
516 ;
517 init32:
518 000003BA 66BB[06840000] mov ebx,call32_call_start+CS_BASE ; Where to go in PM
519
520 call32_enter_pm:
521 000003C0 8CC8 mov ax,cs
522 000003C2 8ED8 mov ds,ax
523 000003C4 FA cli
524 000003C5 8926[0000] mov [SavedSSSP],sp
525 000003C9 8C16[0200] mov [SavedSSSP+2],ss
526 000003CD FC cld
527 000003CE E869FF call a20_test
528 000003D1 7503 jnz .a20ok
529 000003D3 E8DCFE call enable_a20
530
531 .a20ok:
532 000003D6 0F0116[1800] lgdt [call32_gdt] ; Set up GDT
533 000003DB 0F011E[6C00] lidt [call32_pmidt] ; Set up the IDT
534 000003E0 0F20C0 mov eax,cr0
535 000003E3 0C01 or al,1
536 000003E5 0F22C0 mov cr0,eax ; Enter protected mode
537 000003E8 66EA[F0830000]2000 jmp 20h:dword .in_pm+CS_BASE
538
539 bits 32
540 .in_pm:
541 000003F0 31C0 xor eax,eax ; Available for future use...
542 000003F2 8EE0 mov fs,eax
543 000003F4 8EE8 mov gs,eax
544
545 000003F6 B028 mov al,28h ; Set up data segments
546 000003F8 8EC0 mov es,eax
547 000003FA 8ED8 mov ds,eax
548 000003FC 8ED0 mov ss,eax
549
550 000003FE 8B25[0C800000] mov esp,[PMESP+CS_BASE] ; Load protmode %esp if available
551 00000404 FFE3 jmp ebx ; Go to where we need to go
552
553 ;
554 ; This is invoked before first dispatch of the 32-bit code, in 32-bit mode
555 ;
556 call32_call_start:
557 ;
558 ; Point the stack into low memory
559 ; We have: this segment, bounce buffer, then stack+heap
560 ;
561 00000406 BC00800400 mov esp, CS_BASE + 0x20000 + STACK_HEAP_SIZE
562 0000040B 83E4F0 and esp, ~0xf
563
564 ;
565 ; Set up the protmode IDT and the interrupt jump buffers
566 ;
567 0000040E BF[00800000] mov edi,pm_idt+CS_BASE
568
569 ; Form an interrupt gate descriptor
570 ; WARNING: This is broken if pm_idt crosses a 64K boundary;
571 ; however, it can't because of the alignment constraints.
572 00000413 BB[00880000] mov ebx,pm_idt+CS_BASE+8*256
573 00000418 B800EE2000 mov eax,0x0020ee00
574 0000041D 6693 xchg ax,bx
575 0000041F 31C9 xor ecx,ecx
576 00000421 FEC5 inc ch ; ecx <- 256
577
578 00000423 51 push ecx
579 .make_idt:
580 00000424 AB stosd
581 00000425 83C008 add eax,8
582 00000428 93 xchg eax,ebx
583 00000429 AB stosd
584 0000042A 93 xchg eax,ebx
585 0000042B E2F7 loop .make_idt
586
587 0000042D 59 pop ecx
588
589 ; Each entry in the interrupt jump buffer contains
590 ; the following instructions:
591 ;
592 ; 00000000 60 pushad
593 ; 00000001 B0xx mov al,<interrupt#>
594 ; 00000003 E9xxxxxxxx jmp call32_handle_interrupt
595
596 0000042E B860B000E9 mov eax,0xe900b060
597 00000433 BB[D7840000] mov ebx,call32_handle_interrupt+CS_BASE
598 00000438 29FB sub ebx,edi
599
600 .make_ijb:
601 0000043A AB stosd
602 0000043B 284FFE sub [edi-2],cl ; Interrupt #
603 0000043E 93 xchg eax,ebx
604 0000043F 83E808 sub eax,8
605 00000442 AB stosd
606 00000443 93 xchg eax,ebx
607 00000444 E2F4 loop .make_ijb
608
609 ; Now everything is set up for interrupts...
610
611 00000446 6800800100 push dword (BOUNCE_SEG << 4) ; Bounce buffer address
612 0000044B 68[EA840000] push dword call32_syscall+CS_BASE ; Syscall entry point
613 00000450 FB sti ; Interrupts OK now
614 00000451 E8(00800F00) call pm_entry-CS_BASE ; Run the program...
615
616 ; ... on return ...
617 00000456 A3[04800000] mov [Return+CS_BASE],eax
618
619 ; ... fall through to call32_exit ...
620
621 call32_exit:
622 0000045B 66BB[A004] mov bx,call32_done ; Return to command loop
623
624 call32_enter_rm:
625 0000045F FA cli
626 00000460 FC cld
627 00000461 8925[0C800000] mov [PMESP+CS_BASE],esp ; Save exit %esp
628 00000467 31E4 xor esp,esp ; Make sure the high bits are zero
629 00000469 EA[70040000]0800 jmp 08h:.in_pm16 ; Return to 16-bit mode first
630
631 bits 16
632 .in_pm16:
633 00000470 B81000 mov ax,10h ; Real-mode-like segment
634 00000473 8EC0 mov es,ax
635 00000475 8ED8 mov ds,ax
636 00000477 8ED0 mov ss,ax
637 00000479 8EE0 mov fs,ax
638 0000047B 8EE8 mov gs,ax
639
640 0000047D 0F011E[7200] lidt [call32_rmidt] ; Real-mode IDT (rm needs no GDT)
641 00000482 0F20C0 mov eax,cr0
642 00000485 24FE and al,~1
643 00000487 0F22C0 mov cr0,eax
644 0000048A EA[8F04]0008 jmp MY_CS:.in_rm
645
646 .in_rm: ; Back in real mode
647 0000048F 8CC8 mov ax,cs ; Set up sane segments
648 00000491 8ED8 mov ds,ax
649 00000493 8EC0 mov es,ax
650 00000495 8EE0 mov fs,ax
651 00000497 8EE8 mov gs,ax
652 00000499 0FB226[0000] lss sp,[SavedSSSP] ; Restore stack
653 0000049E FFE3 jmp bx ; Go to whereever we need to go...
654
655 call32_done:
656 000004A0 E8B7FE call disable_a20
657 000004A3 FB sti
658 000004A4 A1[0400] mov ax,[Return]
659 000004A7 C3 ret
660
661 ;
662 ; 16-bit support code
663 ;
664 bits 16
665
666 ;
667 ; 16-bit interrupt-handling code
668 ;
669 call32_int_rm:
670 000004A8 9C pushf ; Flags on stack
671 000004A9 0E push cs ; Return segment
672 000004AA 68[B004] push word .cont ; Return address
673 000004AD 6652 push dword edx ; Segment:offset of IVT entry
674 000004AF CB retf ; Invoke IVT routine
675 .cont: ; ... on resume ...
676 000004B0 66BB[E8840000] mov ebx,call32_int_resume+CS_BASE
677 000004B6 E907FF jmp call32_enter_pm ; Go back to PM
678
679 ;
680 ; 16-bit system call handling code
681 ;
682 call32_sys_rm:
683 000004B9 0FA9 pop gs
684 000004BB 0FA1 pop fs
685 000004BD 07 pop es
686 000004BE 1F pop ds
687 000004BF 6661 popad
688 000004C1 669D popfd
689 000004C3 CB retf ; Invoke routine
690 .return:
691 000004C4 669C pushfd
692 000004C6 6660 pushad
693 000004C8 1E push ds
694 000004C9 06 push es
695 000004CA 0FA0 push fs
696 000004CC 0FA8 push gs
697 000004CE 66BB[39850000] mov ebx,call32_sys_resume+CS_BASE
698 000004D4 E9E9FE jmp call32_enter_pm
699
700 ;
701 ; 32-bit support code
702 ;
703 bits 32
704
705 ;
706 ; This is invoked on getting an interrupt in protected mode. At
707 ; this point, we need to context-switch to real mode and invoke
708 ; the interrupt routine.
709 ;
710 ; When this gets invoked, the registers are saved on the stack and
711 ; AL contains the register number.
712 ;
713 call32_handle_interrupt:
714 000004D7 0FB6C0 movzx eax,al
715 000004DA 31DB xor ebx,ebx ; Actually makes the code smaller
716 000004DC 8B1483 mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
717 000004DF 66BB[A804] mov bx,call32_int_rm
718 000004E3 E977FFFFFF jmp call32_enter_rm ; Go to real mode
719
720 call32_int_resume:
721 000004E8 61 popad
722 000004E9 CF iret
723
724 ;
725 ; Syscall invocation. We manifest a structure on the real-mode stack,
726 ; containing the call32sys_t structure from <call32.h> as well as
727 ; the following entries (from low to high address):
728 ; - Target offset
729 ; - Target segment
730 ; - Return offset
731 ; - Return segment (== real mode cs)
732 ; - Return flags
733 ;
734 call32_syscall:
735 000004EA 9C pushfd ; Save IF among other things...
736 000004EB 60 pushad ; We only need to save some, but...
737 000004EC FC cld
738
739 000004ED 0FB73D[00800000] movzx edi,word [SavedSSSP+CS_BASE]
740 000004F4 0FB705[02800000] movzx eax,word [SavedSSSP+CS_BASE+2]
741 000004FB 83EF36 sub edi,54 ; Allocate 54 bytes
742 000004FE 66893D[00800000] mov [SavedSSSP+CS_BASE],di
743 00000505 C1E004 shl eax,4
744 00000508 01C7 add edi,eax ; Create linear address
745
746 0000050A 8B74242C mov esi,[esp+11*4] ; Source regs
747 0000050E 31C9 xor ecx,ecx
748 00000510 B10B mov cl,11 ; 44 bytes to copy
749 00000512 F3A5 rep movsd
750
751 00000514 0FB6442428 movzx eax,byte [esp+10*4] ; Interrupt number
752 ; ecx == 0 here; adding it to the EA makes the
753 ; encoding smaller
754 00000519 8B0481 mov eax,[ecx+eax*4] ; Get IVT entry
755 0000051C AB stosd ; Save in stack frame
756 0000051D B8[C4040008] mov eax,call32_sys_rm.return + (MY_CS << 16) ; Return seg:offs
757 00000522 AB stosd ; Save in stack frame
758 00000523 8B47F4 mov eax,[edi-12] ; Return flags
759 00000526 25D70C2000 and eax,0x200cd7 ; Mask (potentially) unsafe flags
760 0000052B 8947F4 mov [edi-12],eax ; Primary flags entry
761 0000052E 66AB stosw ; Return flags
762
763 00000530 66BB[B904] mov bx,call32_sys_rm
764 00000534 E926FFFFFF jmp call32_enter_rm ; Go to real mode
765
766 ; On return, the 44-byte return structure is on the
767 ; real-mode stack.
768 call32_sys_resume:
769 00000539 0FB735[00800000] movzx esi,word [SavedSSSP+CS_BASE]
770 00000540 0FB705[02800000] movzx eax,word [SavedSSSP+CS_BASE+2]
771 00000547 8B7C2430 mov edi,[esp+12*4] ; Dest regs
772 0000054B C1E004 shl eax,4
773 0000054E 01C6 add esi,eax ; Create linear address
774 00000550 21FF and edi,edi ; NULL pointer?
775 00000552 7502 jnz .do_copy
776 00000554 89F7 .no_copy: mov edi,esi ; Do a dummy copy-to-self
777 00000556 31C9 .do_copy: xor ecx,ecx
778 00000558 B10B mov cl,11 ; 44 bytes
779 0000055A F3A5 rep movsd ; Copy register block
780
781 0000055C 8305[00800000]2C add dword [SavedSSSP+CS_BASE],44 ; Remove from stack
782
783 00000563 61 popad
784 00000564 9D popfd
785 00000565 C3 ret ; Return to 32-bit program

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# $Id: memset.S,v 1.1 2003/04/14 22:28:30 hpa Exp $
#
# memset.S
#
# Simple memset() implementation
#
.text
.globl memset
.type memset, @function
memset:
cld
pushl %edi
pushl %esi
movl 12(%esp),%edi
movzbl 16(%esp),%eax
movl 20(%esp),%esi
imull $0x01010101,%eax
movl %esi,%ecx
shrl $2,%ecx
rep ; stosl
movl %esi,%ecx
andl $3,%ecx
rep ; stosb
movl 12(%esp),%eax
popl %esi
popl %edi
ret
.size memcpy,.-memcpy

Binary file not shown.

View File

@@ -0,0 +1,169 @@
#ident "$Id: msetup.c,v 1.12 2004/12/14 22:46:25 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2003 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.
*
* ----------------------------------------------------------------------- */
/*
* msetup.c
*
* Initialization code for memory-based disk
*/
#include <stdint.h>
#include "memdisk.h"
#include "conio.h"
#include "e820.h"
static inline int get_e820(void)
{
struct e820_info {
uint64_t base;
uint64_t len;
uint32_t type;
} *buf = sys_bounce;
uint32_t copied;
int range_count = 0;
com32sys_t regs;
memset(&regs, 0, sizeof regs);
do {
regs.eax.l = 0x0000e820;
regs.ecx.l = sizeof(*buf);
regs.edx.l = 0x534d4150;
regs.edi.w[0] = OFFS(buf);
regs.es = SEG(buf);
syscall(0x15, &regs, &regs);
copied = (regs.eflags.l & 1) ? 0 : regs.ecx.l;
if ( regs.eax.l != 0x534d4150 || copied < 20 )
break;
printf("e820: %08x%08x %08x%08x %d\n",
(uint32_t)(buf->base >> 32), (uint32_t)buf->base,
(uint32_t)(buf->len >> 32), (uint32_t)buf->len,
buf->type);
insertrange(buf->base, buf->len, buf->type);
range_count++;
} while ( regs.ebx.l );
return !range_count;
}
static inline void get_dos_mem(void)
{
com32sys_t regs;
memset(&regs, 0, sizeof regs);
syscall(0x12, &regs, &regs);
insertrange(0, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
printf(" DOS: %d K\n", regs.eax.w[0]);
}
static inline int get_e801(void)
{
int err;
com32sys_t regs;
memset(&regs, 0, sizeof regs);
regs.eax.w[0] = 0xe801;
syscall(0x15, &regs, &regs);
if ( !(err = regs.eflags.l & 1) ) {
if ( regs.eax.w[0] ) {
insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
}
if ( regs.ebx.w[0] ) {
insertrange(0x1000000, (uint64_t)((uint32_t)regs.ebx.w[0] << 16), 1);
}
printf("e801: %04x %04x\n", regs.eax.w[0], regs.ebx.w[0]);
}
return err;
}
static inline int get_88(void)
{
com32sys_t regs;
int err;
memset(&regs, 0, sizeof regs);
regs.eax.b[1] = 0x88;
syscall(0x15, &regs, &regs);
if ( !(err = regs.eflags.l & 1) ) {
if ( regs.eax.w[0] ) {
insertrange(0x100000, (uint64_t)((uint32_t)regs.eax.w[0] << 10), 1);
}
printf(" 88: %04x\n", regs.eax.w[0]);
}
return err;
}
uint32_t dos_mem = 0; /* 0-1MB */
uint32_t low_mem = 0; /* 1-16MB */
uint32_t high_mem = 0; /* 16+ MB */
void get_mem(void)
{
if ( get_e820() ) {
get_dos_mem();
if ( get_e801() ) {
if ( get_88() ) {
puts("MEMDISK: Unable to obtain memory map\n");
die();
}
}
}
}
#define PW(x) (1ULL << (x))
void parse_mem(void)
{
struct e820range *ep;
dos_mem = low_mem = high_mem = 0;
/* Derive "dos mem", "high mem", and "low mem" from the range array */
for ( ep = ranges ; ep->type != -1 ; ep++ ) {
if ( ep->type == 1 ) {
/* Only look at memory ranges */
if ( ep->start == 0 ) {
if ( ep[1].start > PW(20) )
dos_mem = PW(20);
else
dos_mem = ep[1].start;
}
if ( ep->start <= PW(20) && ep[1].start > PW(20) ) {
if ( ep[1].start > PW(24) )
low_mem = PW(24) - PW(20);
else
low_mem = ep[1].start - PW(20);
}
if ( ep->start <= PW(24) && ep[1].start > PW(24) ) {
if ( ep[1].start > PW(32) )
high_mem = PW(32) - PW(24);
else
high_mem = ep[1].start - PW(24);
}
}
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
#!/usr/bin/perl
## -----------------------------------------------------------------------
##
## Copyright 2001 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.
##
## -----------------------------------------------------------------------
## $Id: postprocess.pl,v 1.4 2004/12/14 22:46:25 hpa Exp $
#
# Postprocess the memdisk binary.
#
eval { use bytes; };
($out,$file16,$file32) = @ARGV;
open(OUT, "> $out\0") or die "$0: Cannot create file: $out\n";
eval { binmode OUT; };
open(FILE, "< $file16\0") or die "$0: Cannot open file: $file16\n";
eval { binmode FILE };
@info = stat(FILE);
$size = $info[7];
$sectors = ($size + 511) >> 9;
$xsize = $sectors << 9;
read(FILE, $f16, $size);
print OUT $f16;
if ( $size != $xsize ) {
# Pad to a sector boundary
print OUT "\0" x ($xsize-$size);
}
seek(OUT, 0x1f1, SEEK_SET); # setup_sects
# All sectors are setup except the first
print OUT pack("C", $sectors-1);
seek(OUT, $xsize, SEEK_SET);
close(FILE);
open(FILE, "+< $file32\0") or die "$0: Cannot open file: $file32\n";
while ( ($n = read(FILE, $f32, 65536)) > 0 ) {
print OUT $f32;
}
close(FILE);
close(OUT);

View File

@@ -0,0 +1,761 @@
#ident "$Id: setup.c,v 1.50 2005/04/29 06:04:45 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2001-2004 H. Peter Anvin - All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, Inc., 53 Temple Place Ste 330,
* Boston MA 02111-1307, USA; either version 2 of the License, or
* (at your option) any later version; incorporated herein by reference.
*
* ----------------------------------------------------------------------- */
#include <stdint.h>
#include "e820.h"
#include "conio.h"
#include "version.h"
#include "memdisk.h"
const char memdisk_version[] =
"MEMDISK " VERSION " " DATE;
const char copyright[] =
"Copyright " FIRSTYEAR "-" COPYYEAR " H. Peter Anvin";
extern const char _binary_memdisk_bin_start[], _binary_memdisk_bin_end[];
extern const char _binary_memdisk_bin_size[]; /* Weird, I know */
struct memdisk_header {
uint16_t int13_offs;
uint16_t int15_offs;
uint16_t patch_offs;
uint16_t total_size;
};
/* The Disk Parameter Table may be required */
typedef union {
struct hd_dpt {
uint16_t max_cyl; /* Max cylinder */
uint8_t max_head; /* Max head */
uint8_t junk1[5]; /* Obsolete junk, leave at zero */
uint8_t ctrl; /* Control byte */
uint8_t junk2[7]; /* More obsolete junk */
} hd;
struct fd_dpt {
uint8_t specify1; /* "First specify byte" */
uint8_t specify2; /* "Second specify byte" */
uint8_t delay; /* Delay until motor turn off */
uint8_t sectors; /* Sectors/track */
uint8_t bps; /* Bytes/sector (02h = 512) */
uint8_t isgap; /* Length of intersector gap */
uint8_t dlen; /* Data length (0FFh) */
uint8_t fgap; /* Formatting gap */
uint8_t ffill; /* Format fill byte */
uint8_t settle; /* Head settle time (ms) */
uint8_t mstart; /* Motor start time */
uint8_t _pad1; /* Padding */
uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */
} fd;
} dpt_t;
struct patch_area {
uint32_t diskbuf;
uint32_t disksize;
uint16_t cmdline_off, cmdline_seg;
uint32_t oldint13;
uint32_t oldint15;
uint16_t olddosmem;
uint8_t bootloaderid;
uint8_t _pad[3];
uint16_t memint1588;
uint16_t cylinders;
uint16_t heads;
uint32_t sectors;
uint32_t mem1mb;
uint32_t mem16mb;
uint8_t driveno;
uint8_t drivetype;
uint8_t drivecnt;
uint8_t configflags;
#define CONFIG_READONLY 0x01
#define CONFIG_RAW 0x02
#define CONFIG_BIGRAW 0x08 /* MUST be 8! */
uint16_t mystack;
uint16_t statusptr;
dpt_t dpt;
};
/* This is the header in the boot sector/setup area */
struct setup_header {
char cmdline[0x1f1];
uint8_t setup_secs;
uint16_t syssize;
uint16_t swap_dev;
uint16_t ram_size;
uint16_t vid_mode;
uint16_t root_dev;
uint16_t boot_flag;
uint16_t jump;
char header[4];
uint16_t version;
uint32_t realmode_swtch;
uint32_t start_sys;
uint8_t type_of_loader;
uint8_t loadflags;
uint16_t setup_move_size;
uint32_t code32_start;
uint32_t ramdisk_image;
uint32_t ramdisk_size;
uint32_t bootsect_kludge;
uint16_t head_end_ptr;
uint16_t pad1;
uint32_t cmd_line_ptr;
uint32_t initrd_addr_max;
};
const struct setup_header * const shdr = (struct setup_header *)(LOW_SEG << 4);
/* Access to high memory */
/* Access to objects in the zero page */
static inline void
wrz_8(uint32_t addr, uint8_t data)
{
*((uint8_t *)addr) = data;
}
static inline void
wrz_16(uint32_t addr, uint16_t data)
{
*((uint16_t *)addr) = data;
}
static inline void
wrz_32(uint32_t addr, uint32_t data)
{
*((uint32_t *)addr) = data;
}
static inline uint8_t
rdz_8(uint32_t addr)
{
return *((uint8_t *)addr);
}
static inline uint16_t
rdz_16(uint32_t addr)
{
return *((uint16_t *)addr);
}
static inline uint32_t
rdz_32(uint32_t addr)
{
return *((uint32_t *)addr);
}
/* Addresses in the zero page */
#define BIOS_INT13 (0x13*4) /* INT 13h vector */
#define BIOS_INT15 (0x15*4) /* INT 15h vector */
#define BIOS_INT1E (0x1E*4) /* INT 1Eh vector */
#define BIOS_INT40 (0x40*4) /* INT 13h vector */
#define BIOS_INT41 (0x41*4) /* INT 41h vector */
#define BIOS_INT46 (0x46*4) /* INT 46h vector */
#define BIOS_BASEMEM 0x413 /* Amount of DOS memory */
#define BIOS_EQUIP 0x410 /* BIOS equipment list */
#define BIOS_HD_COUNT 0x475 /* Number of hard drives present */
/*
* Routine to seek for a command-line item and return a pointer
* to the data portion, if present
*/
/* Magic return values */
#define CMD_NOTFOUND ((char *)-1) /* Not found */
#define CMD_BOOL ((char *)-2) /* Found boolean option */
#define CMD_HASDATA(X) ((int)(X) >= 0)
const char *getcmditem(const char *what)
{
const char *p;
const char *wp = what;
int match = 0;
for ( p = shdr->cmdline ; *p ; p++ ) {
switch ( match ) {
case 0: /* Ground state */
if ( *p == ' ' )
break;
wp = what;
match = 1;
/* Fall through */
case 1: /* Matching */
if ( *wp == '\0' ) {
if ( *p == '=' )
return p+1;
else if ( *p == ' ' )
return CMD_BOOL;
else {
match = 2;
break;
}
}
if ( *p != *wp++ )
match = 2;
break;
case 2: /* Mismatch, skip rest of option */
if ( *p == ' ' )
match = 0; /* Next option */
break;
}
}
/* Check for matching string at end of line */
if ( match == 1 && *wp == '\0' )
return CMD_BOOL;
return CMD_NOTFOUND;
}
/*
* Check to see if this is a gzip image
*/
#define UNZIP_ALIGN 512
extern void _end; /* Symbol signalling end of data */
void unzip_if_needed(uint32_t *where_p, uint32_t *size_p)
{
uint32_t where = *where_p;
uint32_t size = *size_p;
uint32_t zbytes;
uint32_t startrange, endrange;
uint32_t gzdatasize, gzwhere;
uint32_t orig_crc, offset;
uint32_t target = 0;
int i, okmem;
/* Is it a gzip image? */
if (check_zip ((void *)where, size, &zbytes, &gzdatasize,
&orig_crc, &offset) == 0) {
if (offset + zbytes > size) {
/* Assertion failure; check_zip is supposed to guarantee this
never happens. */
puts("internal error: check_zip returned nonsense\n");
die();
}
/* Find a good place to put it: search memory ranges in descending order
until we find one that is legal and fits */
okmem = 0;
for ( i = nranges-1 ; i >= 0 ; i-- ) {
/* We can't use > 4G memory (32 bits only.) Truncate to 2^32-1
so we don't have to deal with funny wraparound issues. */
/* Must be memory */
if ( ranges[i].type != 1 )
continue;
/* Range start */
if ( ranges[i].start >= 0xFFFFFFFF )
continue;
startrange = (uint32_t)ranges[i].start;
/* Range end (0 for end means 2^64) */
endrange = ((ranges[i+1].start >= 0xFFFFFFFF ||
ranges[i+1].start == 0)
? 0xFFFFFFFF : (uint32_t)ranges[i+1].start);
/* Make sure we don't overwrite ourselves */
if ( startrange < (uint32_t)&_end )
startrange = (uint32_t)&_end;
/* Allow for alignment */
startrange = (ranges[i].start + (UNZIP_ALIGN-1)) & ~(UNZIP_ALIGN-1);
/* In case we just killed the whole range... */
if ( startrange >= endrange )
continue;
/* Must be large enough... don't rely on gzwhere for this (wraparound) */
if ( endrange-startrange < gzdatasize )
continue;
/* This is where the gz image should be put if we put it in this range */
gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN-1);
/* Cast to uint64_t just in case we're flush with the top byte */
if ( (uint64_t)where+size >= gzwhere && where < endrange ) {
/* Need to move source data to avoid compressed/uncompressed overlap */
uint32_t newwhere;
if ( gzwhere-startrange < size )
continue; /* Can't fit both old and new */
newwhere = (gzwhere - size) & ~(UNZIP_ALIGN-1);
printf("Moving compressed data from 0x%08x to 0x%08x\n",
where, newwhere);
/* Our memcpy() is OK, because we always move from a higher
address to a lower one */
memcpy((void *)newwhere, (void *)where, size);
where = newwhere;
}
target = gzwhere;
okmem = 1;
break;
}
if ( !okmem ) {
printf("Not enough memory to decompress image (need 0x%08x bytes)\n",
gzdatasize);
die();
}
printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
target, gzdatasize);
*size_p = gzdatasize;
*where_p = (uint32_t)unzip((void *)(where + offset), zbytes,
gzdatasize, orig_crc, (void *)target);
}
}
/*
* Figure out the "geometry" of the disk in question
*/
struct geometry {
uint32_t sectors; /* 512-byte sector count */
uint32_t c, h, s; /* C/H/S geometry */
uint32_t offset; /* Byte offset for disk */
uint8_t type; /* Type byte for INT 13h AH=08h */
uint8_t driveno; /* Drive no */
};
static const struct geometry geometries[] =
{
{ 360*2, 40, 2, 9, 0, 0x01, 0 }, /* 360 K */
{ 720*2, 80, 2, 9, 0, 0x03, 0 }, /* 720 K*/
{ 1200*2, 80, 2, 15, 0, 0x02, 0 }, /* 1200 K */
{ 1440*2, 80, 2, 18, 0, 0x04, 0 }, /* 1440 K */
{ 1680*2, 80, 2, 21, 0, 0x04, 0 }, /* 1680 K */
{ 1722*2, 82, 2, 21, 0, 0x04, 0 }, /* 1722 K */
{ 2880*2, 80, 2, 36, 0, 0x06, 0 }, /* 2880 K */
{ 3840*2, 80, 2, 48, 0, 0x06, 0 }, /* 3840 K */
};
#define known_geometries (sizeof(geometries)/sizeof(struct geometry))
/* Format of a DOS partition table entry */
struct ptab_entry {
uint8_t active;
uint8_t start_h, start_s, start_c;
uint8_t type;
uint8_t end_h, end_s, end_c;
uint32_t start;
uint32_t size;
};
/* Format of a DOSEMU header */
struct dosemu_header {
uint8_t magic[7]; /* DOSEMU\0 */
uint32_t h;
uint32_t s;
uint32_t c;
uint32_t offset;
uint8_t pad[105];
} __attribute__((packed));
#define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
const struct geometry *get_disk_image_geometry(uint32_t where, uint32_t size)
{
static struct geometry hd_geometry = { 0, 0, 0, 0, 0, 0, 0x80 };
struct ptab_entry ptab[4]; /* Partition table buffer */
struct dosemu_header dosemu;
unsigned int sectors, v;
unsigned int max_c, max_h, max_s;
unsigned int c, h, s, offset;
int i;
int drive_specified;
const char *p;
printf("command line: %s\n", shdr->cmdline);
offset = 0;
if ( CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)) )
offset = v;
sectors = (size-offset) >> 9;
for ( i = 0 ; i < known_geometries ; i++ ) {
if ( sectors == geometries[i].sectors ) {
hd_geometry = geometries[i];
break;
}
}
hd_geometry.sectors = sectors;
hd_geometry.offset = offset;
/* Do we have a DOSEMU header? */
memcpy(&dosemu, (char *)where+hd_geometry.offset, sizeof dosemu);
if ( !memcmp("DOSEMU", dosemu.magic, 7) ) {
/* Always a hard disk unless overruled by command-line options */
hd_geometry.driveno = 0x80;
hd_geometry.type = 0;
hd_geometry.c = dosemu.c;
hd_geometry.h = dosemu.h;
hd_geometry.s = dosemu.s;
hd_geometry.offset += dosemu.offset;
sectors = (size-hd_geometry.offset) >> 9;
}
if ( CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)) )
hd_geometry.c = v;
if ( CMD_HASDATA(p = getcmditem("h")) && (v = atou(p)) )
hd_geometry.h = v;
if ( CMD_HASDATA(p = getcmditem("s")) && (v = atou(p)) )
hd_geometry.s = v;
if ( getcmditem("floppy") != CMD_NOTFOUND ) {
hd_geometry.driveno = 0;
if ( hd_geometry.type == 0 )
hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
drive_specified = 1;
} else if ( getcmditem("harddisk") != CMD_NOTFOUND ) {
hd_geometry.driveno = 0x80;
hd_geometry.type = 0;
drive_specified = 1;
}
if ( (hd_geometry.c == 0) || (hd_geometry.h == 0) ||
(hd_geometry.s == 0) ) {
/* Hard disk image, need to examine the partition table for geometry */
memcpy(&ptab, (char *)where+hd_geometry.offset+(512-2-4*16), sizeof ptab);
max_c = max_h = 0; max_s = 1;
for ( i = 0 ; i < 4 ; i++ ) {
if ( ptab[i].type ) {
c = ptab[i].start_c + (ptab[i].start_s >> 6);
s = (ptab[i].start_s & 0x3f);
h = ptab[i].start_h;
if ( max_c < c ) max_c = c;
if ( max_h < h ) max_h = h;
if ( max_s < s ) max_s = s;
c = ptab[i].end_c + (ptab[i].end_s >> 6);
s = (ptab[i].end_s & 0x3f);
h = ptab[i].end_h;
if ( max_c < c ) max_c = c;
if ( max_h < h ) max_h = h;
if ( max_s < s ) max_s = s;
}
}
max_c++; max_h++; /* Convert to count (1-based) */
if ( !hd_geometry.h )
hd_geometry.h = max_h;
if ( !hd_geometry.s )
hd_geometry.s = max_s;
if ( !hd_geometry.c )
hd_geometry.c = sectors/(hd_geometry.h*hd_geometry.s);
}
if ( (size-hd_geometry.offset) & 0x1ff ) {
puts("MEMDISK: Image has fractional end sector\n");
}
if ( sectors % (hd_geometry.h*hd_geometry.s) ) {
puts("MEMDISK: Image seems to have fractional end cylinder\n");
}
if ( (hd_geometry.c*hd_geometry.h*hd_geometry.s) > sectors ) {
puts("MEMDISK: Image appears to be truncated\n");
}
return &hd_geometry;
}
/*
* Jump here if all hope is gone...
*/
void __attribute__((noreturn)) die(void)
{
asm volatile("sti");
for(;;)
asm volatile("hlt");
}
#define STACK_NEEDED 512 /* Number of bytes of stack */
/*
* Actual setup routine
* Returns the drive number (which is then passed in %dl to the
* called routine.)
*/
syscall_t syscall;
void *sys_bounce;
uint32_t setup(syscall_t cs_syscall, void *cs_bounce)
{
unsigned int bin_size = (int) &_binary_memdisk_bin_size;
struct memdisk_header *hptr;
struct patch_area *pptr;
uint16_t driverseg;
uint32_t driverptr, driveraddr;
uint16_t dosmem_k;
uint32_t stddosmem;
const struct geometry *geometry;
int total_size, cmdlinelen;
com32sys_t regs;
uint32_t ramdisk_image, ramdisk_size;
/* Set up global variables */
syscall = cs_syscall;
sys_bounce = cs_bounce;
/* Show signs of life */
printf("%s %s\n", memdisk_version, copyright);
if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) {
puts("MEMDISK: No ramdisk image specified!\n");
die();
}
ramdisk_image = shdr->ramdisk_image;
ramdisk_size = shdr->ramdisk_size;
e820map_init(); /* Initialize memory data structure */
get_mem(); /* Query BIOS for memory map */
parse_mem(); /* Parse memory map */
printf("Ramdisk at 0x%08x, length 0x%08x\n",
ramdisk_image, ramdisk_size);
unzip_if_needed(&ramdisk_image, &ramdisk_size);
geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size);
printf("Disk is %s, %u K, C/H/S = %u/%u/%u\n",
geometry->driveno ? "hard disk" : "floppy",
geometry->sectors >> 1,
geometry->c, geometry->h, geometry->s);
/* Reserve the ramdisk memory */
insertrange(ramdisk_image, ramdisk_size, 2);
parse_mem(); /* Recompute variables */
/* Figure out where it needs to go */
hptr = (struct memdisk_header *) &_binary_memdisk_bin_start;
pptr = (struct patch_area *)(_binary_memdisk_bin_start + hptr->patch_offs);
dosmem_k = rdz_16(BIOS_BASEMEM);
pptr->olddosmem = dosmem_k;
stddosmem = dosmem_k << 10;
/* If INT 15 E820 and INT 12 disagree, go with the most conservative */
if ( stddosmem > dos_mem )
stddosmem = dos_mem;
pptr->driveno = geometry->driveno;
pptr->drivetype = geometry->type;
pptr->cylinders = geometry->c;
pptr->heads = geometry->h;
pptr->sectors = geometry->s;
pptr->disksize = geometry->sectors;
pptr->diskbuf = ramdisk_image + geometry->offset;
pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441;
pptr->bootloaderid = shdr->type_of_loader;
pptr->configflags = 0;
/* Set config flags */
if ( getcmditem("ro") != CMD_NOTFOUND ) {
puts("Marking disk readonly\n");
pptr->configflags |= CONFIG_READONLY;
}
if ( getcmditem("raw") != CMD_NOTFOUND ) {
puts("Using raw access to high memory\n");
pptr->configflags |= CONFIG_RAW;
}
if ( getcmditem("bigraw") != CMD_NOTFOUND ) {
puts("Using raw access to high memory - assuming big real mode\n");
pptr->configflags |= CONFIG_BIGRAW|CONFIG_RAW;
}
/* Set up a drive parameter table */
if ( geometry->driveno & 0x80 ) {
/* Hard disk */
pptr->dpt.hd.max_cyl = geometry->c-1;
pptr->dpt.hd.max_head = geometry->h-1;
pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08: 0;
} else {
/* Floppy - most of these fields are bogus and mimic
a 1.44 MB floppy drive */
pptr->dpt.fd.specify1 = 0xdf;
pptr->dpt.fd.specify2 = 0x02;
pptr->dpt.fd.delay = 0x25;
pptr->dpt.fd.sectors = geometry->s;
pptr->dpt.fd.bps = 0x02;
pptr->dpt.fd.isgap = 0x12;
pptr->dpt.fd.dlen = 0xff;
pptr->dpt.fd.fgap = 0x6c;
pptr->dpt.fd.ffill = 0xf6;
pptr->dpt.fd.settle = 0x0f;
pptr->dpt.fd.mstart = 0x05;
pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E);
}
/* The size is given by hptr->total_size plus the size of the E820
map -- 12 bytes per range; we may need as many as 2 additional
ranges (each insertrange() can worst-case turn 1 area into 3)
plus the terminating range, over what nranges currently show. */
cmdlinelen = strlen(shdr->cmdline)+1;
total_size = hptr->total_size; /* Actual memdisk code */
total_size += (nranges+3)*sizeof(ranges[0]); /* E820 memory ranges */
total_size += cmdlinelen; /* Command line */
total_size += STACK_NEEDED; /* Stack */
printf("Total size needed = %u bytes, allocating %uK\n",
total_size, (total_size+0x3ff) >> 10);
if ( total_size > dos_mem ) {
puts("MEMDISK: Insufficient low memory\n");
die();
}
driveraddr = stddosmem - total_size;
driveraddr &= ~0x3FF;
printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
stddosmem, dos_mem, driveraddr);
/* Reserve this range of memory */
wrz_16(BIOS_BASEMEM, driveraddr >> 10);
insertrange(driveraddr, dos_mem-driveraddr, 2);
parse_mem();
pptr->mem1mb = low_mem >> 10;
pptr->mem16mb = high_mem >> 16;
if ( low_mem == (15 << 20) ) {
/* lowmem maxed out */
uint32_t int1588mem = (high_mem >> 10)+(low_mem >> 10);
pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem;
} else {
pptr->memint1588 = low_mem >> 10;
}
printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n",
pptr->memint1588, pptr->mem1mb, pptr->mem16mb);
driverseg = driveraddr >> 4;
driverptr = driverseg << 16;
/* Anything beyond the end is for the stack */
pptr->mystack = (uint16_t)(stddosmem-driveraddr);
pptr->oldint13 = rdz_32(BIOS_INT13);
pptr->oldint15 = rdz_32(BIOS_INT15);
/* Adjust the E820 table: if there are null ranges (type 0)
at the end, change them to type end of list (-1).
This is necessary for the driver to be able to report end
of list correctly. */
while ( nranges && ranges[nranges-1].type == 0 ) {
ranges[--nranges].type = -1;
}
/* Query drive parameters of this type */
memset(&regs, 0, sizeof regs);
regs.es = 0;
regs.eax.b[1] = 0x08;
regs.edx.b[0] = geometry->driveno;
syscall(0x13, &regs, &regs);
if ( regs.eflags.l & 1 ) {
printf("INT 13 08: Failure, assuming this is the only drive\n");
pptr->drivecnt = 1;
} else {
printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n",
regs.edx.b[0], regs.es, regs.edi.w[0]);
pptr->drivecnt = regs.edx.b[0]+1;
}
/* Pointer to the command line */
pptr->cmdline_off = bin_size + (nranges+1)*sizeof(ranges[0]);
pptr->cmdline_seg = driverseg;
/* Copy driver followed by E820 table followed by command line */
{
unsigned char *dpp = (unsigned char *)(driverseg << 4);
dpp = memcpy_endptr(dpp, &_binary_memdisk_bin_start, bin_size);
dpp = memcpy_endptr(dpp, ranges, (nranges+1)*sizeof(ranges[0]));
dpp = memcpy_endptr(dpp, shdr->cmdline, cmdlinelen+1);
}
/* Install the interrupt handlers */
printf("old: int13 = %08x int15 = %08x\n",
rdz_32(BIOS_INT13), rdz_32(BIOS_INT15));
wrz_32(BIOS_INT13, driverptr+hptr->int13_offs);
wrz_32(BIOS_INT15, driverptr+hptr->int15_offs);
printf("new: int13 = %08x int15 = %08x\n",
rdz_32(BIOS_INT13), rdz_32(BIOS_INT15));
/* Update various BIOS magic data areas (gotta love this shit) */
if ( geometry->driveno & 0x80 ) {
/* Update BIOS hard disk count */
wrz_8(BIOS_HD_COUNT, rdz_8(BIOS_HD_COUNT)+1);
} else {
/* Update BIOS floppy disk count */
uint8_t equip = rdz_8(BIOS_EQUIP);
if ( equip & 1 ) {
if ( (equip & (3 << 6)) != (3 << 6) ) {
equip += (1 << 6);
}
} else {
equip |= 1;
equip &= ~(3 << 6);
}
wrz_8(BIOS_EQUIP, equip);
}
/* Reboot into the new "disk"; this is also a test for the interrupt hooks */
puts("Loading boot sector... ");
memset(&regs, 0, sizeof regs);
// regs.es = 0;
regs.eax.w[0] = 0x0201; /* Read sector */
regs.ebx.w[0] = 0x7c00; /* 0000:7C00 */
regs.ecx.w[0] = 1; /* One sector */
regs.edx.w[0] = geometry->driveno;
syscall(0x13, &regs, &regs);
if ( regs.eflags.l & 1 ) {
puts("MEMDISK: Failed to load new boot sector\n");
die();
}
if ( getcmditem("pause") != CMD_NOTFOUND ) {
puts("press any key to boot... ");
regs.eax.w[0] = 0;
syscall(0x16, &regs, NULL);
}
puts("booting...\n");
/* On return the assembly code will jump to the boot vector */
return geometry->driveno;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
# $Id: start32.S,v 1.1 2003/04/15 19:29:59 hpa Exp $
#
# Simple stub to get us to the right point in the 32-bit code;
# this module must be linked first
#
.text
.globl _start
_start:
jmp setup

Binary file not shown.

View File

@@ -0,0 +1,13 @@
0000000000000000 000000000009bc00 1
000000000009bc00 0000000000004400 2
00000000000e9800 0000000000016800 2
0000000000100000 0000000006ee0000 1
0000000006fe0000 000000000000fc00 3
0000000006fefc00 0000000000000400 4
0000000006ff0000 0000000000002000 2
0000000006ff2000 000000000000e000 1
0000000007000000 0000000000100000 2
00000000fff00000 0000000000100000 2
0000000000586000 0000000000168000 2
000000000009ba00 0000000000000200 2

View File

@@ -0,0 +1,10 @@
0000000000000000 000000000009bc00 1
000000000009bc00 0000000000004400 2
00000000000e9800 0000000000016800 2
0000000000100000 0000000006ee0000 1
0000000006fe0000 000000000000fc00 3
0000000006fefc00 0000000000000400 4
0000000006ff0000 0000000000002000 2
0000000006ff2000 000000000000e000 1
0000000007000000 0000000000100000 2
00000000fff00000 0000000000100000 2

View File

@@ -0,0 +1,14 @@
0000000000000000 000000000009bc00 1
000000000009bc00 0000000000004400 2
00000000000e9800 0000000000016800 2
0000000000100000 0000000006ee0000 1
0000000006fe0000 000000000000fc00 3
0000000006fefc00 0000000000000400 4
0000002000000000 0000001000000000 1
0000000006ff0000 0000000000002000 2
0000000006ff2000 000000000000e000 1
0000000007000000 0000000000100000 2
00000000fff00000 0000000000100000 2
0000000000586000 0000000000168000 2
000000000009ba00 0000000000000200 2

View File

@@ -0,0 +1,390 @@
/*
* unzip.c
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
* puts by Nick Holloway 1993, better puts by Martin Mares 1995
* High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
*
* Adapted for MEMDISK by H. Peter Anvin, April 2003
*/
#include <stdint.h>
#include "memdisk.h"
#include "conio.h"
/*
* gzip declarations
*/
#define OF(args) args
#define STATIC static
#define memzero(s, n) memset ((s), 0, (n))
typedef uint8_t uch;
typedef uint16_t ush;
typedef uint32_t ulg;
#define WSIZE 0x8000 /* Window size must be at least 32k, */
/* and a power of two */
static uch *inbuf; /* input pointer */
static uch window[WSIZE]; /* sliding output window buffer */
static unsigned insize; /* total input bytes read */
static unsigned inbytes; /* valid bytes in inbuf */
static unsigned outcnt; /* bytes in output buffer */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
/* Diagnostic functions */
#ifdef DEBUG
# define Assert(cond,msg) {if(!(cond)) error(msg);}
# define Trace(x) fprintf x
# define Tracev(x) {if (verbose) fprintf x ;}
# define Tracevv(x) {if (verbose>1) fprintf x ;}
# define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
#else
# define Assert(cond,msg)
# define Trace(x)
# define Tracev(x)
# define Tracevv(x)
# define Tracec(c,x)
# define Tracecv(c,x)
#endif
static int fill_inbuf(void);
static void flush_window(void);
static void error(char *m);
static void gzip_mark(void **);
static void gzip_release(void **);
extern ulg crc_32_tab[256];
/* Get byte from input buffer */
static inline uch get_byte(void)
{
if ( inbytes ) {
uch b = *inbuf++;
inbytes--;
return b;
} else {
return fill_inbuf(); /* Input buffer underrun */
}
}
/* Unget byte from input buffer */
static inline void unget_byte(void)
{
inbytes++;
inbuf--;
}
static ulg bytes_out = 0; /* Number of bytes output */
static uch *output_data; /* Output data pointer */
static ulg output_size; /* Number of output bytes expected */
static void *malloc(int size);
static void free(void *where);
static ulg free_mem_ptr, free_mem_end_ptr;
#include "inflate.c"
static void *malloc(int size)
{
void *p;
if (size < 0) error("malloc error");
free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */
p = (void *)free_mem_ptr;
free_mem_ptr += size;
if (free_mem_ptr >= free_mem_end_ptr)
error("out of memory");
return p;
}
static void free(void *where)
{
/* Don't care */
(void)where;
}
static void gzip_mark(void **ptr)
{
*ptr = (void *) free_mem_ptr;
}
static void gzip_release(void **ptr)
{
free_mem_ptr = (long) *ptr;
}
/* ===========================================================================
* Fill the input buffer. This is called only when the buffer is empty
* and at least one byte is really needed.
*/
static int fill_inbuf(void)
{
/* This should never happen. We have already pointed the algorithm
to all the data we have. */
printf("failed\nDecompression error: ran out of input data\n");
die();
}
/* ===========================================================================
* Write the output window window[0..outcnt-1] and update crc and bytes_out.
* (Used for the decompressed data only.)
*/
static void flush_window(void)
{
ulg c = crc; /* temporary variable */
unsigned n;
uch *in, *out, ch;
if ( bytes_out+outcnt > output_size )
error("output buffer overrun");
in = window;
out = output_data;
for (n = 0; n < outcnt; n++) {
ch = *out++ = *in++;
c = crc_32_tab[(c ^ ch) & 0xff] ^ (c >> 8);
}
crc = c;
output_data = out;
bytes_out += (ulg)outcnt;
outcnt = 0;
}
static void error(char *x)
{
printf("failed\nDecompression error: %s\n", x);
die();
}
/* GZIP header */
struct gzip_header {
uint16_t magic;
uint8_t method;
uint8_t flags;
uint32_t timestamp;
uint8_t extra_flags;
uint8_t os_type;
} __attribute__ ((packed));
/* (followed by optional and variable length "extra", "original name",
and "comment" fields) */
struct gzip_trailer {
uint32_t crc;
uint32_t dbytes;
} __attribute__ ((packed));
/* PKZIP header. See
* <http://www.pkware.com/products/enterprise/white_papers/appnote.html>.
*/
struct pkzip_header {
uint32_t magic;
uint16_t version;
uint16_t flags;
uint16_t method;
uint16_t modified_time;
uint16_t modified_date;
uint32_t crc;
uint32_t zbytes;
uint32_t dbytes;
uint16_t filename_len;
uint16_t extra_len;
} __attribute__ ((packed));
/* (followed by optional and variable length "filename" and "extra"
fields) */
/* gzip flag byte */
#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
#define RESERVED 0xC0 /* bit 6,7: reserved */
/* pkzip flag byte */
#define PK_ENCRYPTED 0x01 /* bit 0 set: file is encrypted */
#define PK_DATADESC 0x08 /* bit 3 set: file has trailing "data
descriptor" */
#define PK_UNSUPPORTED 0xFFF0 /* All other bits must be zero */
/* Return 0 if (indata, size) points to a ZIP file, and fill in
compressed data size, uncompressed data size, CRC, and offset of
data.
If indata is not a ZIP file, return -1. */
int check_zip(void *indata, uint32_t size, uint32_t *zbytes_p,
uint32_t *dbytes_p, uint32_t *orig_crc, uint32_t *offset_p) {
struct gzip_header *gzh = (struct gzip_header *)indata;
struct pkzip_header *pkzh = (struct pkzip_header *)indata;
uint32_t offset;
if (gzh->magic == 0x8b1f) {
struct gzip_trailer *gzt = indata + size - sizeof (struct gzip_trailer);
/* We only support method #8, DEFLATED */
if (gzh->method != 8) {
error("gzip file uses invalid method");
return -1;
}
if (gzh->flags & ENCRYPTED) {
error("gzip file is encrypted; not supported");
return -1;
}
if (gzh->flags & CONTINUATION) {
error("gzip file is a continuation file; not supported");
return -1;
}
if (gzh->flags & RESERVED) {
error("gzip file has unsupported flags");
return -1;
}
offset = sizeof (*gzh);
if (gzh->flags & EXTRA_FIELD) {
/* Skip extra field */
unsigned len = *(unsigned *)(indata + offset);
offset += 2 + len;
}
if (gzh->flags & ORIG_NAME) {
/* Discard the old name */
uint8_t *p = indata;
while (p[offset] != 0 && offset < size) {
offset++;
}
offset++;
}
if (gzh->flags & COMMENT) {
/* Discard the comment */
uint8_t *p = indata;
while (p[offset] != 0 && offset < size) {
offset++;
}
offset++;
}
if (offset > size) {
error ("gzip file corrupt");
return -1;
}
*zbytes_p = size - offset - sizeof (struct gzip_trailer);
*dbytes_p = gzt->dbytes;
*orig_crc = gzt->crc;
*offset_p = offset;
return 0;
}
else if (pkzh->magic == 0x04034b50UL) {
/* Magic number matches pkzip file. */
offset = sizeof (*pkzh);
if (pkzh->flags & PK_ENCRYPTED) {
error("pkzip file is encrypted; not supported");
return -1;
}
if (pkzh->flags & PK_DATADESC) {
error("pkzip file uses data_descriptor field; not supported");
return -1;
}
if (pkzh->flags & PK_UNSUPPORTED) {
error("pkzip file has unsupported flags");
return -1;
}
/* We only support method #8, DEFLATED */
if (pkzh->method != 8) {
error("pkzip file uses invalid method");
return -1;
}
/* skip header */
offset = sizeof (*pkzh);
/* skip filename */
offset += pkzh->filename_len;
/* skip extra field */
offset += pkzh->extra_len;
if (offset + pkzh->zbytes > size) {
error ("pkzip file corrupt");
return -1;
}
*zbytes_p = pkzh->zbytes;
*dbytes_p = pkzh->dbytes;
*orig_crc = pkzh->crc;
*offset_p = offset;
return 0;
}
else {
/* Magic number does not match. */
return -1;
}
error ("Internal error in check_zip");
return -1;
}
/*
* Decompress the image, trying to flush the end of it as close
* to end_mem as possible. Return a pointer to the data block,
* and change datalen.
*/
extern void _end;
void *unzip(void *indata, uint32_t zbytes, uint32_t dbytes,
uint32_t orig_crc, void *target)
{
/* Set up the heap; it's the 64K after the bounce buffer */
free_mem_ptr = (ulg)sys_bounce + 0x10000;
free_mem_end_ptr = free_mem_ptr + 0x10000;
/* Set up input buffer */
inbuf = indata;
/* Sometimes inflate() looks beyond the end of the compressed data,
but it always backs up before it is done. So we give it 4 bytes
of slack. */
insize = inbytes = zbytes + 4;
/* Set up output buffer */
outcnt = 0;
output_data = target;
output_size = dbytes;
bytes_out = 0;
makecrc();
gunzip();
/* Verify that gunzip() consumed the entire input. */
if (inbytes != 4)
error("compressed data length error");
/* Check the uncompressed data length and CRC. */
if ( bytes_out != dbytes )
error("uncompressed data length error");
if (orig_crc != CRC_VALUE)
error("crc error");
puts("ok\n");
return target;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
#ident "$Id: version.h,v 1.5 2005/01/03 08:31:59 hpa Exp $"
/* ----------------------------------------------------------------------- *
*
* Copyright 2002 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.
*
* ----------------------------------------------------------------------- */
/*
* version.h
*
* MEMDISK version data
*/
#ifndef MEMDISK_VERSION_H
#define MEMDISK_VERSION_H
#define FIRSTYEAR "2001"
#define COPYYEAR "2005"
#endif