## -----------------------------------------------------------------------
CC = gcc
-CFLAGS = -g -O2 -fomit-frame-pointer -march=i386 \
+CFLAGS = -O2 -fomit-frame-pointer -march=i386 \
-malign-functions=0 -malign-jumps=0 -malign-loops=0
LDFLAGS =
AS = as
$(AS) -o $@ $<
%.s16: %.s
- echo '.code16' > $@
- sed -e 's/\bcall\b/calll/g' -e 's/\bret\b/retl/g' < $< >> $@
+ echo '.code16gcc' | cat - $< > $@
%.s: %.S
$(CC) -x c $(CFLAGS) -Wp,-traditional -E -o $@ $<
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;
+}
+
+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 *);
+ if (!s)
+ s = "(null)";
+
+ 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;
+}
+
#ifndef CONIO_H
#define CONIO_H
+#include <stdint.h>
+#include <stdarg.h>
+
int putchar(int);
int puts(const char *);
+int printf(const char *, ...);
#endif
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;
* This module *MUST* get linked first into the image
*/
- .section ".text", "ax"
+ .text
.code16
/*
/* ------------------- End of setup header --------------------------- */
-/*
- * Canonicalize CS to match the other segments
- */
-start:
- pushw %ds
- pushw $start2
- lret
+LOWSEG = 0x0800 # 0x8000 physical
-start2:
/*
- * Set up the operating environment expected by the C code.
+ * Move ourselves down in memory to reduce the risk of conflicts;
+ * the canonicalize CS to match the other segments...
+ *
* The C code uses 32-bit registers to make sure the high part of
* %esp is zero.
*
- * The C code expects %cs == %ds == %es, and %fs == 0.
+ * The C code expects %cs == %ds == %es == %ss, and %fs == 0.
+ */
+start:
+ movw $LOWSEG,%ax
+ movw %ax,%es
+ movzbw setup_sects,%cx
+ inc %cx # Add one for the boot sector
+ shlw $7,%cx # Convert to dwords
+ xorw %si,%si
+ xorw %di,%di
+ movw %si,%fs # %fs -> zero segment
+ cld
+ rep ; movsl %ds:(%si),%es:(%di)
+ movw %ax,%ds
+ movw %ax,%ss
+ xorl %esp,%esp # Stack at the top of the segment
+ ljmp $LOWSEG, $startc
+
+startc:
+/*
+ * Set up the operating environment expected by the C code.
*/
- .byte 0x66,0x0f,0xb7,0xe4 # movzwl %sp,%esp
- pushw %ds
- popw %es
- xorw %ax,%ax
- movw %ax,%fs
- sti # We may want to kill this?
+ sti # Maybe not?
calll setup # Call the C code
# The setup function returns the drive number,
# which should be returned in %dl
ret
int15_e820:
- cmp edx,534D4150h
+ cmp edx,534D4150h ; "SMAP"
jne near oldint15
cmp ecx,20 ; Need 20 bytes
jb err86
+ push ds
+ push cs
+ pop ds
push edx ; "SMAP"
- push esi
- push edi
and ebx,ebx
jne .renew
- mov ebx,[E820Table]
-.renew: mov esi,ebx
- xor edi,edi
- mov di,cs
- shr di,4
- add edi,E820Buf
- mov ecx,24/2
- call bcopy
- add ebx, byte 12
- pop edi
- pop esi
- mov eax,[cs:E820Buf]
+ mov ebx,E820Table
+.renew:
+ add bx, byte 12 ; Advance to next
+ mov eax,[bx-12] ; Start addr (low)
mov [es:di],eax
- mov eax,[cs:E820Buf+4]
- mov [es:di+4],eax
- mov eax,[cs:E820Buf+12]
- mov [es:di+8],eax
- mov eax,[cs:E820Buf+16]
- mov [es:di+12],eax
- mov eax,[cs:E820Buf+8]
+ 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)
+ mov eax,[bx-4] ; Type
mov [es:di+16],eax
- cmp dword [cs:E820Buf+20], byte -1
+ cmp dword [bx+8], byte -1 ; Type of next = end?
jne .notdone
xor ebx,ebx ; Done with table
.notdone:
pop eax ; "SMAP"
+ pop ds
mov ecx,20 ; Bytes loaded
int15_success:
mov byte [bp+12], 02h ; Clear CF
LastStatus db 0 ; Last return status
- section .bss
- alignb 4
+ alignb 4, db 0
PatchArea equ $ ; This gets filled in by the installer
-Cylinders resw 1 ; Cylinder count
-Heads resw 1 ; Head count
-Sectors resd 1 ; Sector count (zero-extended)
-DiskSize resd 1 ; Size of disk in blocks
-DiskBuf resd 1 ; Linear address of high memory disk
+Cylinders dw 0 ; Cylinder count
+Heads dw 0 ; Head count
+Sectors dd 0 ; Sector count (zero-extended)
+DiskSize dd 0 ; Size of disk in blocks
+DiskBuf dd 0 ; Linear address of high memory disk
-E820Table resd 1 ; E820 table in high memory
-Mem1MB resd 1 ; 1MB-16MB memory amount (1K)
-Mem16MB resd 1 ; 16MB-4G memory amount (64K)
-MemInt1588 resd 1 ; 1MB-65MB memory amount (1K)
+Mem1MB dd 0 ; 1MB-16MB memory amount (1K)
+Mem16MB dd 0 ; 16MB-4G memory amount (64K)
+MemInt1588 dd 0 ; 1MB-65MB memory amount (1K)
-OldInt13 resd 1 ; INT 13h in chain
-OldInt15 resd 1 ; INT 15h in chain
+OldInt13 dd 0 ; INT 13h in chain
+OldInt15 dd 0 ; INT 15h in chain
-OldDosMem resw 1 ; Old position of DOS mem end
+OldDosMem dw 0 ; Old position of DOS mem end
-DriveNo resb 1 ; Our drive number
-DriveType resb 1 ; Our drive type (floppies)
+DriveNo db 0 ; Our drive number
+DriveType db 0 ; Our drive type (floppies)
; End patch area
-Stack resd 2 ; Saved SS:ESP on invocation
-E820Buf resd 6 ; E820 fetch buffer
-SavedAX resw 1 ; AX saved on invocation
+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
--- /dev/null
+#ident "$Id$"
+/* ----------------------------------------------------------------------- *
+ *
+ * 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,
+ * Bostom 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
+
+/* What to call when we're dead */
+extern void __attribute__((noreturn)) die(void);
+
+#endif
*/
#include <stdint.h>
+#include "memdisk.h"
+#include "conio.h"
#include "e820.h"
static inline int get_e820(void)
uint64_t base;
uint64_t len;
uint32_t type;
- } __attribute__((packed));
+ };
struct e820_info buf;
uint32_t lastptr = 0;
- int copied;
- int range_count;
+ uint32_t copied;
+ int range_count = 0;
do {
+ puts("Calling INT 15 E820...\n");
asm volatile("int $0x15 ; "
"jc 1f ; "
"cmpl $0x534d4150, %%eax ; "
"je 2f\n"
"1:\n\t"
- "xorl %%ecx, %%ecx\n"
+ "xorl %0,%0\n"
"2:"
- : "=c" (copied), "=&b" (lastptr)
+ : "=c" (copied), "+b" (lastptr)
: "a" (0x0000e820), "d" (0x534d4150),
- "c" (20), "D" (&buf)
- : "esi", "ebp");
+ "c" (sizeof(buf)), "D" (&buf)
+ : "eax", "edx", "esi", "edi", "ebp");
if ( copied < 20 )
break;
+ printf("BIOS e820: %08x%08x %08x%08x %u\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++;
{
uint16_t dos_kb;
+ puts("Calling INT 12...\n");
asm volatile("int $0x12" : "=a" (dos_kb)
:: "ebx", "ecx", "edx", "esi", "edi", "ebp");
+
+ printf("BIOS 12: %u K DOS memory\n", dos_kb);
insertrange(0, (uint64_t)((uint32_t)dos_kb << 10), 1);
}
-static inline int get_e881(void)
-{
- uint32_t low_mem;
- uint32_t high_mem;
- uint8_t err;
-
- asm volatile("movw $0xe881, %%ax ; "
- "int $0x15 ; "
- "setc %2"
- : "=a" (low_mem), "=b" (high_mem), "=d" (err)
- :: "ecx", "esi", "edi", "ebp");
-
- if ( !err ) {
- if ( low_mem ) {
- insertrange(0x100000, (uint64_t)low_mem << 10, 1);
- }
- if ( high_mem ) {
- insertrange(0x1000000, (uint64_t)high_mem << 16, 1);
- }
- }
-
- return err;
-}
-
static inline int get_e801(void)
{
uint16_t low_mem;
uint16_t high_mem;
uint8_t err;
+ puts("Calling INT 15 E801...\n");
asm volatile("movw $0xe801, %%ax ; "
"int $0x15 ; "
"setc %2"
:: "ecx", "esi", "edi", "ebp");
if ( !err ) {
+ printf("BIOS e801: %u K low mem, %u K high mem\n",
+ low_mem, high_mem << 6);
+
if ( low_mem ) {
insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
}
uint16_t low_mem;
uint8_t err;
+ puts("Calling INT 15 88...\n");
asm volatile("movb $0x88,%%ah ; "
"int $0x15 ; "
"setc %1"
:: "ebx", "ecx", "esi", "edi", "ebp");
if ( !err ) {
+ printf("BIOS 88: %u K extended memory\n", low_mem);
+
if ( low_mem ) {
insertrange(0x100000, (uint64_t)((uint32_t)low_mem << 10), 1);
}
{
if ( get_e820() ) {
get_dos_mem();
- if ( get_e881() ) {
- if ( get_e801() ) {
- if ( get_88() ) {
- /* Running out of ideas here... */
- }
+ if ( get_e801() ) {
+ if ( get_88() ) {
+ puts("MEMDISK: Unable to obtain memory map\n");
+ die();
}
}
}
uint32_t disksize;
uint32_t diskbuf;
- uint32_t e820table;
uint32_t mem1mb;
uint32_t mem16mb;
uint32_t memint1588;
asm volatile("movw %0,%%fs:%1" :: "ri" (data), "m" (*(uint16_t *)addr));
}
static inline void
-wrz_32(uint32_t addr, uint16_t data)
+wrz_32(uint32_t addr, uint32_t data)
{
asm volatile("movl %0,%%fs:%1" :: "ri" (data), "m" (*(uint32_t *)addr));
}
}
/*
+ * Jump here if all hope is gone...
+ */
+void __attribute__((noreturn)) die(void)
+{
+ asm volatile("sti");
+ for(;;)
+ asm volatile("hlt");
+}
+
+/*
* Actual setup routine
* Returns the drive number (which is then passed in %dl to the
* called routine.)
*/
uint32_t setup(void)
{
- unsigned int size = (int) &_binary_memdisk_bin_size;
+ 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;
uint8_t driveno = 0;
uint8_t status;
uint16_t exitcode;
const struct geometry *geometry;
+ int total_size;
/* Show signs of life */
- puts("Memdisk: hello, world!\n");
+ puts("Memdisk: Hello, World!\n");
+
+ if ( !shdr->ramdisk_image || !shdr->ramdisk_size ) {
+ puts("MEMDISK: No ramdisk image specified!\n");
+ die();
+ }
+
+ printf("Test of simple printf...\n");
+ printf("Ramdisk at 0x%08x, length 0x%08x\n",
+ shdr->ramdisk_image, shdr->ramdisk_size);
- for(;;);
+ /* Reserve the ramdisk memory */
+ insertrange(shdr->ramdisk_image, shdr->ramdisk_size, 2);
geometry = get_disk_image_geometry(shdr->ramdisk_image, shdr->ramdisk_size);
get_mem();
parse_mem();
+ printf("dos_mem = %#10x (%u K)\n"
+ "low_mem = %#10x (%u K)\n"
+ "high_mem = %#10x (%u K)\n",
+ dos_mem, dos_mem >> 10,
+ low_mem, low_mem >> 10,
+ high_mem, high_mem >> 10);
+
/* 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);
- if ( hptr->total_size > dos_mem ) {
- /* Badness... */
- }
+ dosmem_k = rdz_16(BIOS_BASEMEM);
+ pptr->olddosmem = dosmem_k;
+ stddosmem = dosmem_k << 10;
- pptr->olddosmem = rdz_16(BIOS_BASEMEM);
pptr->driveno = geometry->driveno;
pptr->drivetype = geometry->type;
pptr->cylinders = geometry->c;
pptr->disksize = geometry->sectors;
pptr->diskbuf = shdr->ramdisk_image;
- driveraddr = dos_mem - hptr->total_size;
+ /* 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 plus the terminating range, over what
+ nranges currently show. */
+
+ total_size = hptr->total_size + (nranges+3)*12;
+ printf("Total size needed = %u bytes\n", total_size);
+
+ 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 */
insertrange(driveraddr, dos_mem-driveraddr, 2);
parse_mem();
/* Claim the memory and copy the driver into place */
wrz_16(BIOS_BASEMEM, dos_mem >> 10);
+ /* Copy driver followed by E820 table */
asm volatile("pushw %%es ; "
"movw %0,%%es ; "
+ "cld ; "
+ "rep ; movsl %%ds:(%%si), %%es:(%%di) ; "
+ "movw %2,%%cx ; "
+ "movw %1,%%si ; "
"rep ; movsl %%ds:(%%si), %%es:(%%di) ; "
"popw %%es"
:: "r" (driverseg),
- "c" (size >> 2),
+ "g" ((uint16_t)((nranges+1)*3)), /* 3 dwords/range */
+ "g" ((uint16_t)ranges),
+ "c" (bin_size >> 2),
"S" (&_binary_memdisk_bin_start),
"D" (0));
: "ebx", "ecx", "edx", "esi", "edi", "ebp");
if ( status ) {
- /* Badness... */
+ puts("MEMDISK: Failed to load new boot sector\n");
+ die();
}
/* On return the assembly code will jump to the boot vector */