diff --git a/src/sys/boot/Makefile.inc b/src/sys/boot/Makefile.inc new file mode 100755 index 0000000..e3011be --- /dev/null +++ b/src/sys/boot/Makefile.inc @@ -0,0 +1,6 @@ +# Common defines for all of /sys/boot/i386/ +# +# $FreeBSD: src/sys/boot/i386/Makefile.inc,v 1.1.2.2 2000/12/28 12:04:04 ps Exp $ + +LOADER_ADDRESS?= 0x200000 +CFLAGS+= -mpreferred-stack-boundary=2 diff --git a/src/sys/boot/boot2/Makefile b/src/sys/boot/boot2/Makefile new file mode 100755 index 0000000..cd404d1 --- /dev/null +++ b/src/sys/boot/boot2/Makefile @@ -0,0 +1,87 @@ +# $FreeBSD: src/sys/boot/i386/boot2/Makefile,v 1.16.2.5 2002/08/07 16:31:53 ru Exp $ + +PROG= boot2 +NOMAN= +STRIP= +BINDIR?= /boot +BINMODE= 444 +CLEANFILES+= boot1 boot1.out boot1.o \ + boot2.ldr boot2.bin boot2.ld boot2.out boot2.o boot2.h \ + sio.o + +NM?= nm + +# A value of 0x80 enables LBA support. +B1FLAGS= 0x80 + +BOOT_COMCONSOLE_PORT?= 0x3f8 +BOOT_COMCONSOLE_SPEED?= 9600 +B2SIOFMT?= 0x3 + +.if exists(${.OBJDIR}/../btx) +BTX= ${.OBJDIR}/../btx +.else +BTX= ${.CURDIR}/../btx +.endif + +ORG1= 0x7c00 +ORG2= 0x1000 + +CFLAGS= -elf -I${.CURDIR}/../btx/lib -I. \ + -Os -fno-builtin -fforce-addr -fdata-sections \ + -malign-functions=0 -malign-jumps=0 -malign-loops=0 -mrtd \ + -mpreferred-stack-boundary=2 \ + -Wall -Waggregate-return -Wbad-function-cast -Wcast-align \ + -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \ + -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings + +LDFLAGS=-nostdlib -static -N + +all: boot1 boot2 + +boot1: boot1.out + objcopy -S -O binary boot1.out ${.TARGET} + +boot1.out: boot1.o + ${LD} ${LDFLAGS} -e start -Ttext ${ORG1} -o ${.TARGET} boot1.o + +boot1.o: boot1.s + ${AS} ${AFLAGS} --defsym FLAGS=${B1FLAGS} ${.IMPSRC} -o ${.TARGET} + +boot2.h: boot1.out + ${NM} -t d ${.ALLSRC} | awk '/([0-9])+ T xread/ \ + { x = $$1 - ORG1; printf("#define XREADORG 0x7%x\n", x) }' \ + ORG1=`printf "%d" ${ORG1}` > boot2.h + +boot2: boot2.ldr boot2.bin ${BTX}/btx/btx + btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr \ + -o boot2.ld -P 1 boot2.bin + @ls -l boot2.ld | awk '{ x = 7680 - $$5; \ + print x " bytes available"; if (x < 0) exit 1 }' + dd if=boot2.ld of=${.TARGET} obs=7680 conv=osync 2>/dev/null + +boot2.ldr: + dd if=/dev/zero of=${.TARGET} bs=512 count=1 2>/dev/null + +boot2.bin: boot2.out + objcopy -S -O binary boot2.out ${.TARGET} + +boot2.out: boot2.o sio.o + ${LD} ${LDFLAGS} -Ttext ${ORG2} -o ${.TARGET} \ + ${BTX}/lib/crt0.o boot2.o sio.o + +boot2.o: boot2.h + +sio.o: sio.s + ${AS} ${AFLAGS} --defsym SIOPRT=${BOOT_COMCONSOLE_PORT} \ + --defsym SIOFMT=${B2SIOFMT} \ + --defsym SIOSPD=${BOOT_COMCONSOLE_SPEED} \ + ${.IMPSRC} -o ${.TARGET} + +install: + ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + boot1 ${DESTDIR}${BINDIR}/boot1 + ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \ + boot2 ${DESTDIR}${BINDIR}/boot2 + +.include diff --git a/src/sys/boot/boot2/boot1.s b/src/sys/boot/boot2/boot1.s new file mode 100755 index 0000000..6a05874 --- /dev/null +++ b/src/sys/boot/boot2/boot1.s @@ -0,0 +1,360 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/boot2/boot1.s,v 1.10.2.3 2001/08/14 22:55:29 jhb Exp $ + +# Memory Locations + .set MEM_REL,0x700 # Relocation address + .set MEM_ARG,0x900 # Arguments + .set MEM_ORG,0x7c00 # Origin + .set MEM_BUF,0x8c00 # Load area + .set MEM_BTX,0x9000 # BTX start + .set MEM_JMP,0x9010 # BTX entry point + .set MEM_USR,0xa000 # Client start + .set BDA_BOOT,0x472 # Boot howto flag + +# Partition Constants + .set PRT_OFF,0x1be # Partition offset + .set PRT_NUM,0x4 # Partitions + .set PRT_BSD,0xa5 # Partition type + +# Flag Bits + .set FL_PACKET,0x80 # Packet mode + +# Misc. Constants + .set SIZ_PAG,0x1000 # Page size + .set SIZ_SEC,0x200 # Sector size + + .globl start + .globl xread + .code16 + +start: jmp main # Start recognizably + +# This is the start of a standard BIOS Parameter Block (BPB). Most bootable +# FAT disks have this at the start of their MBR. While normal BIOS's will +# work fine without this section, IBM's El Torito emulation "fixes" up the +# BPB by writing into the memory copy of the MBR. Rather than have data +# written into our xread routine, we'll define a BPB to work around it. +# The data marked with (T) indicates a field required for a ThinkPad to +# recognize the disk and (W) indicates fields written from IBM BIOS code. +# The use of the BPB is based on what OpenBSD and NetBSD implemented in +# their boot code but the required fields were determined by trial and error. +# +# Note: If additional space is needed in boot1, one solution would be to +# move the "prompt" message data (below) to replace the OEM ID. + + .org 0x03, 0x00 +oemid: .space 0x08, 0x00 # OEM ID + + .org 0x0b, 0x00 +bpb: .word 512 # sector size (T) + .byte 0 # sectors/clustor + .word 0 # reserved sectors + .byte 0 # number of FATs + .word 0 # root entries + .word 0 # small sectors + .byte 0 # media type (W) + .word 0 # sectors/fat + .word 18 # sectors per track (T) + .word 2 # number of heads (T) + .long 0 # hidden sectors (W) + .long 0 # large sectors + + .org 0x24, 0x00 +ebpb: .byte 0 # BIOS physical drive number (W) + + .org 0x25,0x90 +# +# Trampoline used by boot2 to call read to read data from the disk via +# the BIOS. Call with: +# +# %cx:%ax - long - LBA to read in +# %es:(%bx) - caddr_t - buffer to read data into +# %dl - byte - drive to read from +# %dh - byte - num sectors to read +# + +xread: push %ss # Address + pop %ds # data +# +# Setup an EDD disk packet and pass it to read +# +xread.1: # Starting + pushl $0x0 # absolute + push %cx # block + push %ax # number + push %es # Address of + push %bx # transfer buffer + xor %ax,%ax # Number of + movb %dh,%al # blocks to + push %ax # transfer + push $0x10 # Size of packet + mov %sp,%bp # Packet pointer + callw read # Read from disk + lea 0x10(%bp),%sp # Clear stack + lret # To far caller +# +# Load the rest of boot2 and BTX up, copy the parts to the right locations, +# and start it all up. +# + +# +# Setup the segment registers to flat addressing (segment 0) and setup the +# stack to end just below the start of our code. +# +main: cld # String ops inc + xor %cx,%cx # Zero + mov %cx,%es # Address + mov %cx,%ds # data + mov %cx,%ss # Set up + mov $start,%sp # stack +# +# Relocate ourself to MEM_REL. Since %cx == 0, the inc %ch sets +# %cx == 0x100. +# + mov %sp,%si # Source + mov $MEM_REL,%di # Destination + incb %ch # Word count + rep # Copy + movsw # code +# +# If we are on a hard drive, then load the MBR and look for the first +# FreeBSD slice. We use the fake partition entry below that points to +# the MBR when we call nread. The first pass looks for the first active +# FreeBSD slice. The second pass looks for the first non-active FreeBSD +# slice if the first one fails. +# + mov $part4,%si # Partition + cmpb $0x80,%dl # Hard drive? + jb main.4 # No + movb $0x1,%dh # Block count + callw nread # Read MBR + mov $0x1,%cx # Two passes +main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table + movb $0x1,%dh # Partition +main.2: cmpb $PRT_BSD,0x4(%si) # Our partition type? + jne main.3 # No + jcxz main.5 # If second pass + testb $0x80,(%si) # Active? + jnz main.5 # Yes +main.3: add $0x10,%si # Next entry + incb %dh # Partition + cmpb $0x1+PRT_NUM,%dh # In table? + jb main.2 # Yes + dec %cx # Do two + jcxz main.1 # passes +# +# If we get here, we didn't find any FreeBSD slices at all, so print an +# error message and die. +# + mov $msg_part,%si # Message + jmp error # Error +# +# Floppies use partition 0 of drive 0. +# +main.4: xor %dx,%dx # Partition:drive +# +# Ok, we have a slice and drive in %dx now, so use that to locate and load +# boot2. %si references the start of the slice we are looking for, so go +# ahead and load up the first 16 sectors (boot1 + boot2) from that. When +# we read it in, we conveniently use 0x8c00 as our transfer buffer. Thus, +# boot1 ends up at 0x8c00, and boot2 starts at 0x8c00 + 0x200 = 0x8e00. +# The first part of boot2 is the disklabel, which is 0x200 bytes long. +# The second part is BTX, which is thus loaded into 0x9000, which is where +# it also runs from. The boot2.bin binary starts right after the end of +# BTX, so we have to figure out where the start of it is and then move the +# binary to 0xb000. Normally, BTX clients start at MEM_USR, or 0xa000, but +# when we use btxld create boot2, we use an entry point of 0x1000. That +# entry point is relative to MEM_USR; thus boot2.bin starts at 0xb000. +# +main.5: mov %dx,MEM_ARG # Save args + movb $0x10,%dh # Sector count + callw nread # Read disk + mov $MEM_BTX,%bx # BTX + mov 0xa(%bx),%si # Get BTX length and set + add %bx,%si # %si to start of boot2.bin + mov $MEM_USR+SIZ_PAG,%di # Client page 1 + mov $MEM_BTX+0xe*SIZ_SEC,%cx # Byte + sub %si,%cx # count + rep # Relocate + movsb # client + sub %di,%cx # Byte count + xorb %al,%al # Zero assumed bss from + rep # the end of boot2.bin + stosb # up to 0x10000 + callw seta20 # Enable A20 + jmp start+MEM_JMP-MEM_ORG # Start BTX +# +# Enable A20 so we can access memory above 1 meg. +# +seta20: cli # Disable interrupts +seta20.1: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.1 # Yes + movb $0xd1,%al # Command: Write + outb %al,$0x64 # output port +seta20.2: inb $0x64,%al # Get status + testb $0x2,%al # Busy? + jnz seta20.2 # Yes + movb $0xdf,%al # Enable + outb %al,$0x60 # A20 + sti # Enable interrupts + retw # To caller +# +# Trampoline used to call read from within boot1. +# +nread: mov $MEM_BUF,%bx # Transfer buffer + mov 0x8(%si),%ax # Get + mov 0xa(%si),%cx # LBA + push %cs # Read from + callw xread.1 # disk + jnc return # If success, return + mov $msg_read,%si # Otherwise, set the error + # message and fall through to + # the error routine +# +# Print out the error message pointed to by %ds:(%si) followed +# by a prompt, wait for a keypress, and then reboot the machine. +# +error: callw putstr # Display message + mov $prompt,%si # Display + callw putstr # prompt + xorb %ah,%ah # BIOS: Get + int $0x16 # keypress + movw $0x1234, BDA_BOOT # Do a warm boot + ljmp $0xffff,$0x0 # reboot the machine +# +# Display a null-terminated string using the BIOS output. +# +putstr.0: mov $0x7,%bx # Page:attribute + movb $0xe,%ah # BIOS: Display + int $0x10 # character +putstr: lodsb # Get char + testb %al,%al # End of string? + jne putstr.0 # No + +# +# Overused return code. ereturn is used to return an error from the +# read function. Since we assume putstr succeeds, we (ab)use the +# same code when we return from putstr. +# +ereturn: movb $0x1,%ah # Invalid + stc # argument +return: retw # To caller +# +# Reads sectors from the disk. If EDD is enabled, then check if it is +# installed and use it if it is. If it is not installed or not enabled, then +# fall back to using CHS. Since we use a LBA, if we are using CHS, we have to +# fetch the drive parameters from the BIOS and divide it out ourselves. +# Call with: +# +# %dl - byte - drive number +# stack - 10 bytes - EDD Packet +# +read: push %dx # Save + movb $0x8,%ah # BIOS: Get drive + int $0x13 # parameters + movb %dh,%ch # Max head number + pop %dx # Restore + jc return # If error + andb $0x3f,%cl # Sectors per track + jz ereturn # If zero + cli # Disable interrupts + mov 0x8(%bp),%eax # Get LBA + push %dx # Save + movzbl %cl,%ebx # Divide by + xor %edx,%edx # sectors + div %ebx # per track + movb %ch,%bl # Max head number + movb %dl,%ch # Sector number + inc %bx # Divide by + xorb %dl,%dl # number + div %ebx # of heads + movb %dl,%bh # Head number + pop %dx # Restore + cmpl $0x3ff,%eax # Cylinder number supportable? + sti # Enable interrupts + ja read.7 # No, try EDD + xchgb %al,%ah # Set up cylinder + rorb $0x2,%al # number + orb %ch,%al # Merge + inc %ax # sector + xchg %ax,%cx # number + movb %bh,%dh # Head number + subb %ah,%al # Sectors this track + mov 0x2(%bp),%ah # Blocks to read + cmpb %ah,%al # To read + jb read.2 # this + movb %ah,%al # track +read.2: mov $0x5,%di # Try count +read.3: les 0x4(%bp),%bx # Transfer buffer + push %ax # Save + movb $0x2,%ah # BIOS: Read + int $0x13 # from disk + pop %bx # Restore + jnc read.4 # If success + dec %di # Retry? + jz read.6 # No + xorb %ah,%ah # BIOS: Reset + int $0x13 # disk system + xchg %bx,%ax # Block count + jmp read.3 # Continue +read.4: movzbw %bl,%ax # Sectors read + add %ax,0x8(%bp) # Adjust + jnc read.5 # LBA, + incw 0xa(%bp) # transfer +read.5: shlb %bl # buffer + add %bl,0x5(%bp) # pointer, + sub %al,0x2(%bp) # block count + ja read # If not done +read.6: retw # To caller +read.7: testb $FL_PACKET,%cs:MEM_REL+flags-start # LBA support enabled? + jz ereturn # No, so return an error + mov $0x55aa,%bx # Magic + push %dx # Save + movb $0x41,%ah # BIOS: Check + int $0x13 # extensions present + pop %dx # Restore + jc return # If error, return an error + cmp $0xaa55,%bx # Magic? + jne ereturn # No, so return an error + testb $0x1,%cl # Packet interface? + jz ereturn # No, so return an error + mov %bp,%si # Disk packet + movb $0x42,%ah # BIOS: Extended + int $0x13 # read + retw # To caller + +# Messages + +msg_read: .asciz "Read" +msg_part: .asciz "Boot" + +prompt: .asciz " error\r\n" + +flags: .byte FLAGS # Flags + + .org PRT_OFF,0x90 + +# Partition table + + .fill 0x30,0x1,0x0 +part4: .byte 0x80, 0x00, 0x01, 0x00 + .byte 0xa5, 0xff, 0xff, 0xff + .byte 0x00, 0x00, 0x00, 0x00 + .byte 0x50, 0xc3, 0x00, 0x00 # 50000 sectors long, bleh + + .word 0xaa55 # Magic number diff --git a/src/sys/boot/boot2/boot2.c b/src/sys/boot/boot2/boot2.c new file mode 100755 index 0000000..214b4d4 --- /dev/null +++ b/src/sys/boot/boot2/boot2.c @@ -0,0 +1,812 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD: src/sys/boot/i386/boot2/boot2.c,v 1.28.2.6 2002/03/31 18:12:50 pb Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include + +#include + +#include "boot2.h" +#include "lib.h" + +#define RBX_ASKNAME 0x0 /* -a */ +#define RBX_SINGLE 0x1 /* -s */ +#define RBX_DFLTROOT 0x5 /* -r */ +#define RBX_KDB 0x6 /* -d */ +#define RBX_CONFIG 0xa /* -c */ +#define RBX_VERBOSE 0xb /* -v */ +#define RBX_SERIAL 0xc /* -h */ +#define RBX_CDROM 0xd /* -C */ +#define RBX_GDB 0xf /* -g */ +#define RBX_DUAL 0x1d /* -D */ +#define RBX_PROBEKBD 0x1e /* -P */ +#define RBX_NOINTR 0x1f /* -n */ + +#define RBX_MASK 0xffff + +#define PATH_CONFIG "/boot.config" +#define PATH_BOOT3 "/boot/loader" +#define PATH_KERNEL "/kernel" + +#define ARGS 0x900 +#define NOPT 12 +#define BSIZEMAX 16384 +#define NDEV 5 +#define MEM_BASE 0x12 +#define MEM_EXT 0x15 +#define V86_CY(x) ((x) & 1) +#define V86_ZR(x) ((x) & 0x40) + +#define DRV_HARD 0x80 +#define DRV_MASK 0x7f + +#define TYPE_AD 0 +#define TYPE_WD 1 +#define TYPE_WFD 2 +#define TYPE_FD 3 +#define TYPE_DA 4 + +extern uint32_t _end; + +static const char optstr[NOPT] = "DhaCcdgnPrsv"; +static const unsigned char flags[NOPT] = { + RBX_DUAL, + RBX_SERIAL, + RBX_ASKNAME, + RBX_CDROM, + RBX_CONFIG, + RBX_KDB, + RBX_GDB, + RBX_NOINTR, + RBX_PROBEKBD, + RBX_DFLTROOT, + RBX_SINGLE, + RBX_VERBOSE +}; + +static const char *const dev_nm[] = {"ad", "wd", " ", "fd", "da"}; +static const unsigned dev_maj[] = {30, 0, 1, 2, 4}; + +static struct dsk { + unsigned drive; + unsigned type; + unsigned unit; + unsigned slice; + unsigned part; + unsigned start; + int init; + int meta; +} dsk; +static char cmd[512]; +static char kname[1024]; +static uint32_t opts; +static struct bootinfo bootinfo; +static int ls; +static uint32_t fs_off; +static uint8_t ioctrl = 0x1; + +void exit(int); +static void load(const char *); +static int parse(char *); +static ino_t lookup(const char *); +static int xfsread(ino_t, void *, size_t); +static ssize_t fsread(ino_t, void *, size_t); +static int dskread(void *, unsigned, unsigned); +static int printf(const char *,...); +static int putchar(int); +static void *memcpy(void *, const void *, size_t); +static void *malloc(size_t); +static uint32_t memsize(int); +static int drvread(void *, unsigned, unsigned); +static int keyhit(unsigned); +static int xputc(int); +static int xgetc(int); +static int getc(int); + +static inline void +readfile(const char *fname, void *buf, size_t size) +{ + ino_t ino; + + if ((ino = lookup(fname))) + fsread(ino, buf, size); +} + +static inline int +strcmp(const char *s1, const char *s2) +{ + for (; *s1 == *s2 && *s1; s1++, s2++); + return (u_char)*s1 - (u_char)*s2; +} + +static inline int +fsfind(const char *name, ino_t * ino) +{ + char buf[DEV_BSIZE]; + struct dirent *d; + char *s; + ssize_t n; + + fs_off = 0; + while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) + for (s = buf; s < buf + DEV_BSIZE;) { + d = (void *)s; + if (ls) + printf("%s ", d->d_name); + else if (!strcmp(name, d->d_name)) { + *ino = d->d_fileno; + return d->d_type; + } + s += d->d_reclen; + } + if (n != -1 && ls) + putchar('\n'); + return 0; +} + +static inline int +getchar(void) +{ + int c; + + c = xgetc(0); + if (c == '\r') + c = '\n'; + return c; +} + +static inline void +getstr(char *str, int size) +{ + char *s; + int c; + + s = str; + do { + switch (c = getchar()) { + case 0: + break; + case '\b': + case '\177': + if (s > str) { + s--; + putchar('\b'); + putchar(' '); + } else + c = 0; + break; + case '\n': + *s = 0; + break; + default: + if (s - str < size - 1) + *s++ = c; + } + if (c) + putchar(c); + } while (c != '\n'); +} + +static inline uint32_t +drvinfo(int drive) +{ + v86.addr = 0x13; + v86.eax = 0x800; + v86.edx = DRV_HARD + drive; + v86int(); + if (V86_CY(v86.efl)) + return 0x4f010f; + return ((v86.ecx & 0xc0) << 18) | ((v86.ecx & 0xff00) << 8) | + (v86.edx & 0xff00) | (v86.ecx & 0x3f); +} + +static inline void +putc(int c) +{ + v86.addr = 0x10; + v86.eax = 0xe00 | (c & 0xff); + v86.ebx = 0x7; + v86int(); +} + +int +main(void) +{ + int autoboot, i; + + v86.ctl = V86_FLAGS; + dsk.drive = *(uint8_t *)PTOV(ARGS); + dsk.type = dsk.drive & DRV_HARD ? TYPE_AD : TYPE_FD; + dsk.unit = dsk.drive & DRV_MASK; + dsk.slice = *(uint8_t *)PTOV(ARGS + 1) + 1; + bootinfo.bi_version = BOOTINFO_VERSION; + bootinfo.bi_size = sizeof(bootinfo); + bootinfo.bi_basemem = memsize(MEM_BASE); + bootinfo.bi_extmem = memsize(MEM_EXT); + bootinfo.bi_memsizes_valid++; + for (i = 0; i < N_BIOS_GEOM; i++) + bootinfo.bi_bios_geom[i] = drvinfo(i); + autoboot = 2; + readfile(PATH_CONFIG, cmd, sizeof(cmd)); + if (*cmd) { + printf("%s: %s", PATH_CONFIG, cmd); + if (parse(cmd)) + autoboot = 0; + *cmd = 0; + } + if (autoboot && !*kname) { + if (autoboot == 2) { + memcpy(kname, PATH_BOOT3, sizeof(PATH_BOOT3)); + if (!keyhit(0x37)) { + load(kname); + autoboot = 1; + } + } + if (autoboot == 1) + memcpy(kname, PATH_KERNEL, sizeof(PATH_KERNEL)); + } + for (;;) { + printf(" \n>> FreeBSD/i386 BOOT\n" + "Default: %u:%s(%u,%c)%s\n" + "boot: ", + dsk.drive & DRV_MASK, dev_nm[dsk.type], dsk.unit, + 'a' + dsk.part, kname); + if (ioctrl & 0x2) + sio_flush(); + if (!autoboot || keyhit(0x5a)) + getstr(cmd, sizeof(cmd)); + else + putchar('\n'); + autoboot = 0; + if (parse(cmd)) + putchar('\a'); + else + load(kname); + } +} + +/* XXX - Needed for btxld to link the boot2 binary; do not remove. */ +void +exit(int x) +{ +} + +static void +load(const char *fname) +{ + union { + struct exec ex; + Elf32_Ehdr eh; + } hdr; + Elf32_Phdr ep[2]; + Elf32_Shdr es[2]; + caddr_t p; + ino_t ino; + uint32_t addr, x; + int fmt, i, j; + + if (!(ino = lookup(fname))) { + if (!ls) + printf("No %s\n", fname); + return; + } + if (xfsread(ino, &hdr, sizeof(hdr))) + return; + if (N_GETMAGIC(hdr.ex) == ZMAGIC) + fmt = 0; + else if (IS_ELF(hdr.eh)) + fmt = 1; + else { + printf("Invalid %s\n", "format"); + return; + } + if (fmt == 0) { + addr = hdr.ex.a_entry & 0xffffff; + p = PTOV(addr); + fs_off = PAGE_SIZE; + if (xfsread(ino, p, hdr.ex.a_text)) + return; + p += roundup2(hdr.ex.a_text, PAGE_SIZE); + if (xfsread(ino, p, hdr.ex.a_data)) + return; + p += hdr.ex.a_data + roundup2(hdr.ex.a_bss, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + memcpy(p, &hdr.ex.a_syms, sizeof(hdr.ex.a_syms)); + p += sizeof(hdr.ex.a_syms); + if (hdr.ex.a_syms) { + if (xfsread(ino, p, hdr.ex.a_syms)) + return; + p += hdr.ex.a_syms; + if (xfsread(ino, p, sizeof(int))) + return; + x = *(uint32_t *)p; + p += sizeof(int); + x -= sizeof(int); + if (xfsread(ino, p, x)) + return; + p += x; + } + } else { + fs_off = hdr.eh.e_phoff; + for (j = i = 0; i < hdr.eh.e_phnum && j < 2; i++) { + if (xfsread(ino, ep + j, sizeof(ep[0]))) + return; + if (ep[j].p_type == PT_LOAD) + j++; + } + for (i = 0; i < 2; i++) { + p = PTOV(ep[i].p_paddr & 0xffffff); + fs_off = ep[i].p_offset; + if (xfsread(ino, p, ep[i].p_filesz)) + return; + } + p += roundup2(ep[1].p_memsz, PAGE_SIZE); + bootinfo.bi_symtab = VTOP(p); + if (hdr.eh.e_shnum == hdr.eh.e_shstrndx + 3) { + fs_off = hdr.eh.e_shoff + sizeof(es[0]) * + (hdr.eh.e_shstrndx + 1); + if (xfsread(ino, &es, sizeof(es))) + return; + for (i = 0; i < 2; i++) { + memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); + p += sizeof(es[i].sh_size); + fs_off = es[i].sh_offset; + if (xfsread(ino, p, es[i].sh_size)) + return; + p += es[i].sh_size; + } + } + addr = hdr.eh.e_entry & 0xffffff; + } + bootinfo.bi_esymtab = VTOP(p); + bootinfo.bi_kernelname = VTOP(fname); + bootinfo.bi_bios_dev = dsk.drive; + __exec((caddr_t)addr, RB_BOOTINFO | (opts & RBX_MASK), + MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part), + 0, 0, 0, VTOP(&bootinfo)); +} + +static int +parse(char *arg) +{ + char *p, *q; + int drv, c, i; + + while ((c = *arg++)) { + if (c == ' ' || c == '\t' || c == '\n') + continue; + for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++); + if (*p) + *p++ = 0; + if (c == '-') { + while ((c = *arg++)) { + for (i = 0; c != optstr[i]; i++) + if (i == NOPT - 1) + return -1; + opts ^= 1 << flags[i]; + } + if (opts & 1 << RBX_PROBEKBD) { + i = *(uint8_t *)PTOV(0x496) & 0x10; + printf("Keyboard: %s\n", i ? "yes" : "no"); + if (!i) + opts |= 1 << RBX_DUAL | 1 << RBX_SERIAL; + opts &= ~(1 << RBX_PROBEKBD); + } + ioctrl = opts & 1 << RBX_DUAL ? 0x3 : + opts & 1 << RBX_SERIAL ? 0x2 : 0x1; + if (ioctrl & 0x2) + sio_init(); + } else { + for (q = arg--; *q && *q != '('; q++); + if (*q) { + drv = -1; + if (arg[1] == ':') { + if (*arg < '0' || *arg > '9') + return -1; + drv = *arg - '0'; + arg += 2; + } + if (q - arg != 2) + return -1; + for (i = 0; arg[0] != dev_nm[i][0] || + arg[1] != dev_nm[i][1]; i++) + if (i == NDEV - 1) + return -1; + dsk.type = i; + arg += 3; + if (arg[1] != ',' || *arg < '0' || *arg > '9') + return -1; + dsk.unit = *arg - '0'; + arg += 2; + dsk.slice = WHOLE_DISK_SLICE; + if (arg[1] == ',') { + if (*arg < '0' || *arg > '0' + NDOSPART) + return -1; + if ((dsk.slice = *arg - '0')) + dsk.slice++; + arg += 2; + } + if (arg[1] != ')' || *arg < 'a' || *arg > 'p') + return -1; + dsk.part = *arg - 'a'; + arg += 2; + if (drv == -1) + drv = dsk.unit; + dsk.drive = (dsk.type == TYPE_WD || + dsk.type == TYPE_AD || + dsk.type == TYPE_DA ? DRV_HARD : 0) + drv; + dsk.meta = 0; + fsread(0, NULL, 0); + } + if ((i = p - arg - !*(p - 1))) { + if (i >= sizeof(kname)) + return -1; + memcpy(kname, arg, i + 1); + } + } + arg = p; + } + return 0; +} + +static ino_t +lookup(const char *path) +{ + char name[MAXNAMLEN + 1]; + const char *s; + ino_t ino; + ssize_t n; + int dt; + + ino = ROOTINO; + dt = DT_DIR; + for (;;) { + if (*path == '/') + path++; + if (!*path) + break; + for (s = path; *s && *s != '/'; s++); + if ((n = s - path) > MAXNAMLEN) + return 0; + ls = *path == '?' && n == 1 && !*s; + memcpy(name, path, n); + name[n] = 0; + if ((dt = fsfind(name, &ino)) <= 0) + break; + path = s; + } + return dt == DT_REG ? ino : 0; +} +static int +xfsread(ino_t inode, void *buf, size_t nbyte) +{ + if (fsread(inode, buf, nbyte) != nbyte) { + printf("Invalid %s\n", "format"); + return -1; + } + return 0; +} + +static ssize_t +fsread(ino_t inode, void *buf, size_t nbyte) +{ + static struct fs fs; + static struct dinode din; + static char *blkbuf; + static ufs_daddr_t *indbuf; + static ino_t inomap; + static ufs_daddr_t blkmap, indmap; + static unsigned fsblks; + char *s; + ufs_daddr_t lbn, addr; + size_t n, nb, off; + + if (!dsk.meta) { + if (!blkbuf) + blkbuf = malloc(BSIZEMAX); + inomap = 0; + if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) + return -1; + memcpy(&fs, blkbuf, sizeof(fs)); + if (fs.fs_magic != FS_MAGIC) { + printf("Not ufs\n"); + return -1; + } + fsblks = fs.fs_bsize >> DEV_BSHIFT; + dsk.meta++; + } + if (!inode) + return 0; + if (inomap != inode) { + if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), + fsblks)) + return -1; + din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)]; + inomap = inode; + fs_off = 0; + blkmap = indmap = 0; + } + s = buf; + if (nbyte > (n = din.di_size - fs_off)) + nbyte = n; + nb = nbyte; + while (nb) { + lbn = lblkno(&fs, fs_off); + if (lbn < NDADDR) + addr = din.di_db[lbn]; + else { + if (indmap != din.di_ib[0]) { + if (!indbuf) + indbuf = malloc(BSIZEMAX); + if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), + fsblks)) + return -1; + indmap = din.di_ib[0]; + } + addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; + } + n = dblksize(&fs, &din, lbn); + if (blkmap != addr) { + if (dskread(blkbuf, fsbtodb(&fs, addr), n >> DEV_BSHIFT)) + return -1; + blkmap = addr; + } + off = blkoff(&fs, fs_off); + n -= off; + if (n > nb) + n = nb; + memcpy(s, blkbuf + off, n); + s += n; + fs_off += n; + nb -= n; + } + return nbyte; +} + +static int +dskread(void *buf, unsigned lba, unsigned nblk) +{ + static char *sec; + struct dos_partition *dp; + struct disklabel *d; + unsigned sl, i; + + if (!dsk.meta) { + if (!sec) + sec = malloc(DEV_BSIZE); + dsk.start = 0; + if (drvread(sec, DOSBBSECTOR, 1)) + return -1; + dp = (void *)(sec + DOSPARTOFF); + sl = dsk.slice; + if (sl < BASE_SLICE) { + for (i = 0; i < NDOSPART; i++) + if (dp[i].dp_typ == DOSPTYP_386BSD && + (dp[i].dp_flag & 0x80 || sl < BASE_SLICE)) { + sl = BASE_SLICE + i; + if (dp[i].dp_flag & 0x80 || + dsk.slice == COMPATIBILITY_SLICE) + break; + } + if (dsk.slice == WHOLE_DISK_SLICE) + dsk.slice = sl; + } + if (sl != WHOLE_DISK_SLICE) { + if (sl != COMPATIBILITY_SLICE) + dp += sl - BASE_SLICE; + if (dp->dp_typ != DOSPTYP_386BSD) { + printf("Invalid %s\n", "slice"); + return -1; + } + dsk.start = dp->dp_start; + } + if (drvread(sec, dsk.start + LABELSECTOR, 1)) + return -1; + d = (void *)(sec + LABELOFFSET); + if (d->d_magic != DISKMAGIC || d->d_magic2 != DISKMAGIC) { + if (dsk.part != RAW_PART) { + printf("Invalid %s\n", "label"); + return -1; + } + } else { + if (!dsk.init) { + if (d->d_type == DTYPE_SCSI) + dsk.type = TYPE_DA; + dsk.init++; + } + if (dsk.part >= d->d_npartitions || + !d->d_partitions[dsk.part].p_size) { + printf("Invalid %s\n", "partition"); + return -1; + } + dsk.start = d->d_partitions[dsk.part].p_offset; + } + } + return drvread(buf, dsk.start + lba, nblk); +} + +static int +printf(const char *fmt,...) +{ + static const char digits[16] = "0123456789abcdef"; + va_list ap; + char buf[10]; + char *s; + unsigned r, u; + int c; + + va_start(ap, fmt); + while ((c = *fmt++)) { + if (c == '%') { + c = *fmt++; + switch (c) { + case 'c': + putchar(va_arg(ap, int)); + continue; + case 's': + for (s = va_arg(ap, char *); *s; s++) + putchar(*s); + continue; + case 'u': + case 'x': + r = c == 'u' ? 10U : 16U; + u = va_arg(ap, unsigned); + s = buf; + do + *s++ = digits[u % r]; + while (u /= r); + while (--s >= buf) + putchar(*s); + continue; + } + } + putchar(c); + } + va_end(ap); + return 0; +} + +static int +putchar(int c) +{ + if (c == '\n') + xputc('\r'); + return xputc(c); +} + +static void * +memcpy(void *dst, const void *src, size_t size) +{ + const char *s; + char *d; + + for (d = dst, s = src; size; size--) + *d++ = *s++; + return dst; +} + +static void * +malloc(size_t size) +{ + static uint32_t next; + void *p; + + if (!next) + next = roundup2(__base + _end, 0x10000) - __base; + p = (void *)next; + next += size; + return p; +} + +static uint32_t +memsize(int type) +{ + v86.addr = type; + v86.eax = 0x8800; + v86int(); + return v86.eax; +} + +static int +drvread(void *buf, unsigned lba, unsigned nblk) +{ + static unsigned c = 0x2d5c7c2f; + + printf("%c\b", c = c << 8 | c >> 24); + v86.ctl = V86_ADDR | V86_CALLF | V86_FLAGS; + v86.addr = XREADORG; /* call to xread in boot1 */ + v86.es = VTOPSEG(buf); + v86.eax = lba; + v86.ebx = VTOPOFF(buf); + v86.ecx = lba >> 16; + v86.edx = nblk << 8 | dsk.drive; + v86int(); + v86.ctl = V86_FLAGS; + if (V86_CY(v86.efl)) { + printf("Disk error 0x%x (lba=0x%x)\n", v86.eax >> 8 & 0xff, + lba); + return -1; + } + return 0; +} + +static int +keyhit(unsigned ticks) +{ + uint32_t t0, t1; + + if (opts & 1 << RBX_NOINTR) + return 0; + t0 = 0; + for (;;) { + if (xgetc(1)) + return 1; + t1 = *(uint32_t *)PTOV(0x46c); + if (!t0) + t0 = t1; + if (t1 < t0 || t1 >= t0 + ticks) + return 0; + } +} + +static int +xputc(int c) +{ + if (ioctrl & 0x1) + putc(c); + if (ioctrl & 0x2) + sio_putc(c); + return c; +} + +static int +xgetc(int fn) +{ + if (opts & 1 << RBX_NOINTR) + return 0; + for (;;) { + if (ioctrl & 0x1 && getc(1)) + return fn ? 1 : getc(0); + if (ioctrl & 0x2 && sio_ischar()) + return fn ? 1 : sio_getc(); + if (fn) + return 0; + } +} + +static int +getc(int fn) +{ + v86.addr = 0x16; + v86.eax = fn << 8; + v86int(); + return fn == 0 ? v86.eax & 0xff : !V86_ZR(v86.efl); +} diff --git a/src/sys/boot/boot2/lib.h b/src/sys/boot/boot2/lib.h new file mode 100755 index 0000000..44d1f10 --- /dev/null +++ b/src/sys/boot/boot2/lib.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD: src/sys/boot/i386/boot2/lib.h,v 1.2 1999/08/28 00:40:02 peter Exp $ + */ + +void sio_init(void); +void sio_flush(void); +void sio_putc(int); +int sio_getc(void); +int sio_ischar(void); diff --git a/src/sys/boot/boot2/sio.s b/src/sys/boot/boot2/sio.s new file mode 100755 index 0000000..1e8da20 --- /dev/null +++ b/src/sys/boot/boot2/sio.s @@ -0,0 +1,80 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/boot2/sio.s,v 1.4 1999/08/28 00:40:02 peter Exp $ + + .set SIO_PRT,SIOPRT # Base port + .set SIO_FMT,SIOFMT # 8N1 + .set SIO_DIV,(115200/SIOSPD) # 115200 / SPD + + .globl sio_init + .globl sio_flush + .globl sio_putc + .globl sio_getc + .globl sio_ischar + +# void sio_init(void) + +sio_init: movw $SIO_PRT+0x3,%dx # Data format reg + movb $SIO_FMT|0x80,%al # Set format + outb %al,(%dx) # and DLAB + pushl %edx # Save + subb $0x3,%dl # Divisor latch reg + movw $SIO_DIV,%ax # Set + outw %ax,(%dx) # BPS + popl %edx # Restore + movb $SIO_FMT,%al # Clear + outb %al,(%dx) # DLAB + incl %edx # Modem control reg + movb $0x3,%al # Set RTS, + outb %al,(%dx) # DTR + incl %edx # Line status reg + +# void sio_flush(void) + +sio_flush.0: call sio_getc.1 # Get character +sio_flush: call sio_ischar # Check for character + jnz sio_flush.0 # Till none + ret # To caller + +# void sio_putc(int c) + +sio_putc: movw $SIO_PRT+0x5,%dx # Line status reg + xor %ecx,%ecx # Timeout + movb $0x40,%ch # counter +sio_putc.1: inb (%dx),%al # Transmitter + testb $0x20,%al # buffer empty? + loopz sio_putc.1 # No + jz sio_putc.2 # If timeout + movb 0x4(%esp,1),%al # Get character + subb $0x5,%dl # Transmitter hold reg + outb %al,(%dx) # Write character +sio_putc.2: ret $0x4 # To caller + +# int sio_getc(void) + +sio_getc: call sio_ischar # Character available? + jz sio_getc # No +sio_getc.1: subb $0x5,%dl # Receiver buffer reg + inb (%dx),%al # Read character + ret # To caller + +# int sio_ischar(void) + +sio_ischar: movw $SIO_PRT+0x5,%dx # Line status register + xorl %eax,%eax # Zero + inb (%dx),%al # Received data + andb $0x1,%al # ready? + ret # To caller diff --git a/src/sys/boot/btx/Makefile b/src/sys/boot/btx/Makefile new file mode 100755 index 0000000..9a65f19 --- /dev/null +++ b/src/sys/boot/btx/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD: src/sys/boot/i386/btx/Makefile,v 1.6 1999/08/28 00:40:03 peter Exp $ + +SUBDIR= btx btxldr lib + +.include diff --git a/src/sys/boot/btx/btx/Makefile b/src/sys/boot/btx/btx/Makefile new file mode 100755 index 0000000..cdefb50 --- /dev/null +++ b/src/sys/boot/btx/btx/Makefile @@ -0,0 +1,36 @@ +# $FreeBSD: src/sys/boot/i386/btx/btx/Makefile,v 1.7.2.2 2000/12/28 12:08:22 ps Exp $ + +M4?= m4 + +.if defined(PAGING) +M4FLAGS+= -DPAGING +.endif + +.if defined(BOOT_BTX_NOHANG) +BOOT_BTX_FLAGS=0x1 +.else +BOOT_BTX_FLAGS=0x0 +.endif + +AFLAGS+= --defsym BTX_FLAGS=${BOOT_BTX_FLAGS} + +ORG= 0x9000 + +all: btx + +btx: btx.o +.if ${OBJFORMAT} == aout + ${LD} -nostdlib -N -s -T ${ORG} -o btx.out btx.o + dd if=btx.out of=${.TARGET} ibs=32 skip=1 +.else + ${LD} -N -e start -Ttext ${ORG} -o btx.out btx.o + objcopy -S -O binary btx.out ${.TARGET} +.endif + +btx.o: btx.s + (cd ${.CURDIR}; ${M4} ${M4FLAGS} btx.s) | \ + ${AS} ${AFLAGS} -o ${.TARGET} + +CLEANFILES+= btx btx.out btx.o + +.include diff --git a/src/sys/boot/btx/btx/btx.s b/src/sys/boot/btx/btx/btx.s new file mode 100755 index 0000000..0bcf0a9 --- /dev/null +++ b/src/sys/boot/btx/btx/btx.s @@ -0,0 +1,1080 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/btx/btx.s,v 1.15.2.4 2000/12/28 12:08:22 ps Exp $ + +# +# Memory layout. +# + .set MEM_BTX,0x1000 # Start of BTX memory + .set MEM_ESP0,0x1800 # Supervisor stack + .set MEM_BUF,0x1800 # Scratch buffer + .set MEM_ESP1,0x1e00 # Link stack + .set MEM_IDT,0x1e00 # IDT + .set MEM_TSS,0x1f98 # TSS + .set MEM_MAP,0x2000 # I/O bit map + .set MEM_DIR,0x4000 # Page directory + .set MEM_TBL,0x5000 # Page tables + .set MEM_ORG,0x9000 # BTX code + .set MEM_USR,0xa000 # Start of user memory +# +# Paging control. +# + .set PAG_SIZ,0x1000 # Page size + .set PAG_CNT,0x1000 # Pages to map +# +# Segment selectors. +# + .set SEL_SCODE,0x8 # Supervisor code + .set SEL_SDATA,0x10 # Supervisor data + .set SEL_RCODE,0x18 # Real mode code + .set SEL_RDATA,0x20 # Real mode data + .set SEL_UCODE,0x28|3 # User code + .set SEL_UDATA,0x30|3 # User data + .set SEL_TSS,0x38 # TSS +# +# Task state segment fields. +# + .set TSS_ESP0,0x4 # PL 0 ESP + .set TSS_SS0,0x8 # PL 0 SS + .set TSS_ESP1,0xc # PL 1 ESP + .set TSS_MAP,0x66 # I/O bit map base +# +# System calls. +# + .set SYS_EXIT,0x0 # Exit + .set SYS_EXEC,0x1 # Exec +# +# V86 constants. +# + .set V86_FLG,0x208eff # V86 flag mask + .set V86_STK,0x400 # V86 stack allowance +# +# Dump format control bytes. +# + .set DMP_X16,0x1 # Word + .set DMP_X32,0x2 # Long + .set DMP_MEM,0x4 # Memory + .set DMP_EOL,0x8 # End of line +# +# Screen defaults and assumptions. +# + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +# +# BIOS Data Area locations. +# + .set BDA_MEM,0x413 # Free memory + .set BDA_KEYFLAGS,0x417 # Keyboard shift-state flags + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position + .set BDA_BOOT,0x472 # Boot howto flag +# +# Derivations, for brevity. +# + .set _ESP0H,MEM_ESP0>>0x8 # Byte 1 of ESP0 + .set _ESP1H,MEM_ESP1>>0x8 # Byte 1 of ESP1 + .set _TSSIO,MEM_MAP-MEM_TSS # TSS I/O base + .set _TSSLM,MEM_DIR-MEM_TSS-1 # TSS limit + .set _IDTLM,MEM_TSS-MEM_IDT-1 # IDT limit +# +# Code segment. +# + .globl start + .code16 +start: # Start of code +# +# BTX header. +# +btx_hdr: .byte 0xeb # Machine ID + .byte 0xe # Header size + .ascii "BTX" # Magic + .byte 0x1 # Major version + .byte 0x1 # Minor version + .byte BTX_FLAGS # Flags + .word PAG_CNT-MEM_ORG>>0xc # Paging control + .word break-start # Text size + .long 0x0 # Entry address +# +# Initialization routine. +# +init: cli # Disable interrupts + xor %ax,%ax # Zero/segment + mov %ax,%ss # Set up + mov $MEM_ESP0,%sp # stack + mov %ax,%es # Address + mov %ax,%ds # data + pushl $0x2 # Clear + popfl # flags +# +# Initialize memory. +# + mov $MEM_IDT,%di # Memory to initialize + mov $(MEM_ORG-MEM_IDT)/2,%cx # Words to zero + push %di # Save + rep # Zero-fill + stosw # memory + pop %di # Restore +# +# Create IDT. +# + mov $idtctl,%si # Control string +init.1: lodsb # Get entry + cbw # count + xchg %ax,%cx # as word + jcxz init.4 # If done + lodsb # Get segment + xchg %ax,%dx # P:DPL:type + lodsw # Get control + xchg %ax,%bx # set + lodsw # Get handler offset + mov $SEL_SCODE,%dh # Segment selector +init.2: shr %bx # Handle this int? + jnc init.3 # No + mov %ax,(%di) # Set handler offset + mov %dh,0x2(%di) # and selector + mov %dl,0x5(%di) # Set P:DPL:type + add $0x4,%ax # Next handler +init.3: lea 0x8(%di),%di # Next entry + loop init.2 # Till set done + jmp init.1 # Continue +# +# Initialize TSS. +# +init.4: movb $_ESP0H,TSS_ESP0+1(%di) # Set ESP0 + movb $SEL_SDATA,TSS_SS0(%di) # Set SS0 + movb $_ESP1H,TSS_ESP1+1(%di) # Set ESP1 + movb $_TSSIO,TSS_MAP(%di) # Set I/O bit map base +ifdef(`PAGING',` +# +# Create page directory. +# + xor %edx,%edx # Page + mov $PAG_SIZ>>0x8,%dh # size + xor %eax,%eax # Zero + mov $MEM_DIR,%di # Page directory + mov $PAG_CNT>>0xa,%cl # Entries + mov $MEM_TBL|0x7,%ax # First entry +init.5: stosl # Write entry + add %dx,%ax # To next + loop init.5 # Till done +# +# Create page tables. +# + mov $MEM_TBL,%di # Page table + mov $PAG_CNT>>0x8,%ch # Entries + xor %ax,%ax # Start address +init.6: mov $0x7,%al # Set U:W:P flags + cmp btx_hdr+0x8,%cx # Standard user page? + jb init.7 # Yes + cmp $PAG_CNT-MEM_BTX>>0xc,%cx # BTX memory? + jae init.7 # No or first page + and $~0x2,%al # Clear W flag + cmp $PAG_CNT-MEM_USR>>0xc,%cx # User page zero? + jne init.7 # No + testb $0x80,btx_hdr+0x7 # Unmap it? + jz init.7 # No + and $~0x1,%al # Clear P flag +init.7: stosl # Set entry + add %edx,%eax # Next address + loop init.6 # Till done +') +# +# Bring up the system. +# + mov $0x2820,%bx # Set protected mode + callw setpic # IRQ offsets + lidt idtdesc # Set IDT +ifdef(`PAGING',` + xor %eax,%eax # Set base + mov $MEM_DIR>>0x8,%ah # of page + mov %eax,%cr3 # directory +') + lgdt gdtdesc # Set GDT + mov %cr0,%eax # Switch to protected +ifdef(`PAGING',` + or $0x80000001,%eax # mode and enable paging +',` + or $0x01,%eax # mode +') + mov %eax,%cr0 # + ljmp $SEL_SCODE,$init.8 # To 32-bit code + .code32 +init.8: xorl %ecx,%ecx # Zero + movb $SEL_SDATA,%cl # To 32-bit + movw %cx,%ss # stack +# +# Launch user task. +# + movb $SEL_TSS,%cl # Set task + ltr %cx # register + movl $MEM_USR,%edx # User base address + movzwl %ss:BDA_MEM,%eax # Get free memory + shll $0xa,%eax # To bytes + subl $0x1000,%eax # Less arg space + subl %edx,%eax # Less base + movb $SEL_UDATA,%cl # User data selector + pushl %ecx # Set SS + pushl %eax # Set ESP + push $0x202 # Set flags (IF set) + push $SEL_UCODE # Set CS + pushl btx_hdr+0xc # Set EIP + pushl %ecx # Set GS + pushl %ecx # Set FS + pushl %ecx # Set DS + pushl %ecx # Set ES + pushl %edx # Set EAX + movb $0x7,%cl # Set remaining +init.9: push $0x0 # general + loop init.9 # registers + popa # and initialize + popl %es # Initialize + popl %ds # user + popl %fs # segment + popl %gs # registers + iret # To user mode +# +# Exit routine. +# +exit: cli # Disable interrupts + movl $MEM_ESP0,%esp # Clear stack +# +# Turn off paging. +# + movl %cr0,%eax # Get CR0 +ifdef(`PAGING',` + andl $~0x80000000,%eax # Disable + movl %eax,%cr0 # paging +') + xorl %ecx,%ecx # Zero +ifdef(`PAGING',` + movl %ecx,%cr3 # Flush TLB +') +# +# To 16 bits. +# + ljmpw $SEL_RCODE,$exit.1 # Reload CS + .code16 +exit.1: mov $SEL_RDATA,%cl # 16-bit selector + mov %cx,%ss # Reload SS + mov %cx,%ds # Load + mov %cx,%es # remaining + mov %cx,%fs # segment + mov %cx,%gs # registers +# +# To real-address mode. +# + dec %ax # Switch to + mov %eax,%cr0 # real mode + ljmp $0x0,$exit.2 # Reload CS +exit.2: xor %ax,%ax # Real mode segment + mov %ax,%ss # Reload SS + mov %ax,%ds # Address data + mov $0x7008,%bx # Set real mode + callw setpic # IRQ offsets + lidt ivtdesc # Set IVT +# +# Reboot or await reset. +# + sti # Enable interrupts + testb $0x1,btx_hdr+0x7 # Reboot? +exit.3: jz exit.3 # No + movw $0x1234, BDA_BOOT # Do a warm boot + ljmp $0xffff,$0x0 # reboot the machine +# +# Set IRQ offsets by reprogramming 8259A PICs. +# +setpic: in $0x21,%al # Save master + push %ax # IMR + in $0xa1,%al # Save slave + push %ax # IMR + movb $0x11,%al # ICW1 to + outb %al,$0x20 # master, + outb %al,$0xa0 # slave + movb %bl,%al # ICW2 to + outb %al,$0x21 # master + movb %bh,%al # ICW2 to + outb %al,$0xa1 # slave + movb $0x4,%al # ICW3 to + outb %al,$0x21 # master + movb $0x2,%al # ICW3 to + outb %al,$0xa1 # slave + movb $0x1,%al # ICW4 to + outb %al,$0x21 # master, + outb %al,$0xa1 # slave + pop %ax # Restore slave + outb %al,$0xa1 # IMR + pop %ax # Restore master + outb %al,$0x21 # IMR + retw # To caller + .code32 +# +# Initiate return from V86 mode to user mode. +# +inthlt: hlt # To supervisor mode +# +# Exception jump table. +# +intx00: push $0x0 # Int 0x0: #DE + jmp ex_noc # Divide error + push $0x1 # Int 0x1: #DB + jmp ex_noc # Debug + push $0x3 # Int 0x3: #BP + jmp ex_noc # Breakpoint + push $0x4 # Int 0x4: #OF + jmp ex_noc # Overflow + push $0x5 # Int 0x5: #BR + jmp ex_noc # BOUND range exceeded + push $0x6 # Int 0x6: #UD + jmp ex_noc # Invalid opcode + push $0x7 # Int 0x7: #NM + jmp ex_noc # Device not available + push $0x8 # Int 0x8: #DF + jmp except # Double fault + push $0xa # Int 0xa: #TS + jmp except # Invalid TSS + push $0xb # Int 0xb: #NP + jmp except # Segment not present + push $0xc # Int 0xc: #SS + jmp except # Stack segment fault + push $0xd # Int 0xd: #GP + jmp ex_v86 # General protection + push $0xe # Int 0xe: #PF + jmp except # Page fault +intx10: push $0x10 # Int 0x10: #MF + jmp ex_noc # Floating-point error +# +# Handle #GP exception. +# +ex_v86: testb $0x2,0x12(%esp,1) # V86 mode? + jz except # No + jmp v86mon # To monitor +# +# Save a zero error code. +# +ex_noc: pushl (%esp,1) # Duplicate int no + movb $0x0,0x4(%esp,1) # Fake error code +# +# Handle exception. +# +except: cld # String ops inc + pushl %ds # Save + pushl %es # most + pusha # registers + movb $0x6,%al # Push loop count + testb $0x2,0x3a(%esp,1) # V86 mode? + jnz except.1 # Yes + pushl %gs # Set GS + pushl %fs # Set FS + pushl %ds # Set DS + pushl %es # Set ES + movb $0x2,%al # Push loop count + cmpw $SEL_SCODE,0x44(%esp,1) # Supervisor mode? + jne except.1 # No + pushl %ss # Set SS + leal 0x50(%esp,1),%eax # Set + pushl %eax # ESP + jmp except.2 # Join common code +except.1: pushl 0x50(%esp,1) # Set GS, FS, DS, ES + decb %al # (if V86 mode), and + jne except.1 # SS, ESP +except.2: push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + movl %esp,%ebx # Stack frame + movl $dmpfmt,%esi # Dump format string + movl $MEM_BUF,%edi # Buffer + pushl %edi # Dump to + call dump # buffer + popl %esi # and + call putstr # display + leal 0x18(%esp,1),%esp # Discard frame + popa # Restore + popl %es # registers + popl %ds # saved + cmpb $0x3,(%esp,1) # Breakpoint? + je except.3 # Yes + jmp exit # Exit +except.3: leal 0x8(%esp,1),%esp # Discard err, int no + iret # From interrupt +# +# Return to user mode from V86 mode. +# +intrtn: cld # String ops inc + pushl %ds # Address + popl %es # data + leal 0x3c(%ebp),%edx # V86 Segment registers + movl MEM_TSS+TSS_ESP1,%esi # Link stack pointer + lodsl # INT_V86 args pointer + movl %esi,%ebx # Saved exception frame + testl %eax,%eax # INT_V86 args? + jz intrtn.2 # No + movl $MEM_USR,%edi # User base + movl 0x1c(%esi),%ebx # User ESP + movl %eax,(%edi,%ebx,1) # Restore to user stack + leal 0x8(%edi,%eax,1),%edi # Arg segment registers + testb $0x4,-0x6(%edi) # Return flags? + jz intrtn.1 # No + movl 0x30(%ebp),%eax # Get V86 flags + movw %ax,0x18(%esi) # Set user flags +intrtn.1: leal 0x10(%esi),%ebx # Saved exception frame + xchgl %edx,%esi # Segment registers + movb $0x4,%cl # Update seg regs + rep # in INT_V86 + movsl # args +intrtn.2: movl %edx,%esi # Segment registers + leal 0x28(%ebp),%edi # Set up seg + movb $0x4,%cl # regs for + rep # later + movsl # pop + movl %ebx,%esi # Restore exception + movb $0x5,%cl # frame to + rep # supervisor + movsl # stack + movl %esi,MEM_TSS+TSS_ESP1 # Link stack pointer + popa # Restore + leal 0x8(%esp,1),%esp # Discard err, int no + popl %es # Restore + popl %ds # user + popl %fs # segment + popl %gs # registers + iret # To user mode +# +# V86 monitor. +# +v86mon: cld # String ops inc + pushl $SEL_SDATA # Set up for + popl %ds # flat addressing + pusha # Save registers + movl %esp,%ebp # Address stack frame + movzwl 0x2c(%ebp),%edi # Load V86 CS + shll $0x4,%edi # To linear + movl 0x28(%ebp),%esi # Load V86 IP + addl %edi,%esi # Code pointer + xorl %ecx,%ecx # Zero + movb $0x2,%cl # 16-bit operands + xorl %eax,%eax # Zero +v86mon.1: lodsb # Get opcode + cmpb $0x66,%al # Operand size prefix? + jne v86mon.2 # No + movb $0x4,%cl # 32-bit operands + jmp v86mon.1 # Continue +v86mon.2: cmpb $0xf4,%al # HLT? + jne v86mon.3 # No + cmpl $inthlt+0x1,%esi # Is inthlt? + jne v86mon.7 # No (ignore) + jmp intrtn # Return to user mode +v86mon.3: cmpb $0xf,%al # Prefixed instruction? + jne v86mon.4 # No + cmpb $0x09,(%esi) # Is it a WBINVD? + je v86wbinvd # Yes + cmpb $0x30,(%esi) # Is it a WRMSR? + je v86wrmsr # Yes + cmpb $0x32,(%esi) # Is it a RDMSR? + je v86rdmsr # Yes + cmpb $0x20,(%esi) # Is this a + jne v86mon.4 # MOV EAX,CR0 + cmpb $0xc0,0x1(%esi) # instruction? + je v86mov # Yes +v86mon.4: cmpb $0xfa,%al # CLI? + je v86cli # Yes + cmpb $0xfb,%al # STI? + je v86sti # Yes + movzwl 0x38(%ebp),%ebx # Load V86 SS + shll $0x4,%ebx # To offset + pushl %ebx # Save + addl 0x34(%ebp),%ebx # Add V86 SP + movl 0x30(%ebp),%edx # Load V86 flags + cmpb $0x9c,%al # PUSHF/PUSHFD? + je v86pushf # Yes + cmpb $0x9d,%al # POPF/POPFD? + je v86popf # Yes + cmpb $0xcd,%al # INT imm8? + je v86intn # Yes + cmpb $0xcf,%al # IRET/IRETD? + je v86iret # Yes + popl %ebx # Restore + popa # Restore + jmp except # Handle exception +v86mon.5: movl %edx,0x30(%ebp) # Save V86 flags +v86mon.6: popl %edx # V86 SS adjustment + subl %edx,%ebx # Save V86 + movl %ebx,0x34(%ebp) # SP +v86mon.7: subl %edi,%esi # From linear + movl %esi,0x28(%ebp) # Save V86 IP + popa # Restore + leal 0x8(%esp,1),%esp # Discard int no, error + iret # To V86 mode +# +# Emulate MOV EAX,CR0. +# +v86mov: movl %cr0,%eax # CR0 to + movl %eax,0x1c(%ebp) # saved EAX + incl %esi # Adjust IP +# +# Return from emulating a 0x0f prefixed instruction +# +v86preret: incl %esi # Adjust IP + jmp v86mon.7 # Finish up +# +# Emulate WBINVD +# +v86wbinvd: wbinvd # Write back and invalidate + # cache + jmp v86preret # Finish up +# +# Emulate WRMSR +# +v86wrmsr: movl 0x18(%ebp),%ecx # Get user's %ecx (MSR to write) + movl 0x14(%ebp),%edx # Load the value + movl 0x1c(%ebp),%eax # to write + wrmsr # Write MSR + jmp v86preret # Finish up +# +# Emulate RDMSR +# +v86rdmsr: movl 0x18(%ebp),%ecx # MSR to read + rdmsr # Read the MSR + movl %eax,0x1c(%ebp) # Return the value of + movl %edx,0x14(%ebp) # the MSR to the user + jmp v86preret # Finish up +# +# Emulate CLI. +# +v86cli: andb $~0x2,0x31(%ebp) # Clear IF + jmp v86mon.7 # Finish up +# +# Emulate STI. +# +v86sti: orb $0x2,0x31(%ebp) # Set IF + jmp v86mon.7 # Finish up +# +# Emulate PUSHF/PUSHFD. +# +v86pushf: subl %ecx,%ebx # Adjust SP + cmpb $0x4,%cl # 32-bit + je v86pushf.1 # Yes + data16 # 16-bit +v86pushf.1: movl %edx,(%ebx) # Save flags + jmp v86mon.6 # Finish up +# +# Emulate IRET/IRETD. +# +v86iret: movzwl (%ebx),%esi # Load V86 IP + movzwl 0x2(%ebx),%edi # Load V86 CS + leal 0x4(%ebx),%ebx # Adjust SP + movl %edi,0x2c(%ebp) # Save V86 CS + xorl %edi,%edi # No ESI adjustment +# +# Emulate POPF/POPFD (and remainder of IRET/IRETD). +# +v86popf: cmpb $0x4,%cl # 32-bit? + je v86popf.1 # Yes + movl %edx,%eax # Initialize + data16 # 16-bit +v86popf.1: movl (%ebx),%eax # Load flags + addl %ecx,%ebx # Adjust SP + andl $V86_FLG,%eax # Merge + andl $~V86_FLG,%edx # the + orl %eax,%edx # flags + jmp v86mon.5 # Finish up +# +# trap int 15, function 87 +# reads %es:%si from saved registers on stack to find a GDT containing +# source and destination locations +# reads count of words from saved %cx +# returns success by setting %ah to 0 +# +int15_87: pushl %eax # Save + pushl %ebx # some information + pushl %esi # onto the stack. + pushl %edi + xorl %eax,%eax # clean EAX + xorl %ebx,%ebx # clean EBX + movl 0x4(%ebp),%esi # Get user's ESI + movl 0x3C(%ebp),%ebx # store ES + movw %si,%ax # store SI + shll $0x4,%ebx # Make it a seg. + addl %eax,%ebx # ebx=(es<<4)+si + movb 0x14(%ebx),%al # Grab the + movb 0x17(%ebx),%ah # necessary + shll $0x10,%eax # information + movw 0x12(%ebx),%ax # from + movl %eax,%esi # the + movb 0x1c(%ebx),%al # GDT in order to + movb 0x1f(%ebx),%ah # have %esi offset + shll $0x10,%eax # of source and %edi + movw 0x1a(%ebx),%ax # of destination. + movl %eax,%edi + pushl %ds # Make: + popl %es # es = ds + pushl %ecx # stash ECX + xorl %ecx,%ecx # highw of ECX is clear + movw 0x18(%ebp),%cx # Get user's ECX + shll $0x1,%ecx # Convert from num words to num + # bytes + rep # repeat... + movsb # perform copy. + popl %ecx # Restore + popl %edi + popl %esi # previous + popl %ebx # register + popl %eax # values. + movb $0x0,0x1d(%ebp) # set ah = 0 to indicate + # success + andb $0xfe,%dl # clear CF + jmp v86mon.5 # Finish up + +# +# Reboot the machine by setting the reboot flag and exiting +# +reboot: orb $0x1,btx_hdr+0x7 # Set the reboot flag + jmp exit # Terminate BTX and reboot + +# +# Emulate INT imm8... also make sure to check if it's int 15/87 +# +v86intn: lodsb # Get int no + cmpb $0x19,%al # is it int 19? + je reboot # yes, reboot the machine + cmpb $0x15,%al # is it int 15? + jne v86intn.3 # no, skip parse + pushl %eax # stash EAX + movl 0x1c(%ebp),%eax # user's saved EAX + cmpb $0x87,%ah # is it the memcpy subfunction? + jne v86intn.1 # no, keep checking + popl %eax # get the stack straight + jmp int15_87 # it's our cue +v86intn.1: cmpw $0x4f53,%ax # is it the delete key callout? + jne v86intn.2 # no, handle the int normally + movb BDA_KEYFLAGS,%al # get the shift key state + andb $0xc,%al # mask off just Ctrl and Alt + cmpb $0xc,%al # are both Ctrl and Alt down? + jne v86intn.2 # no, handle the int normally + popl %eax # restore EAX + jmp reboot # reboot the machine +v86intn.2: popl %eax # restore EAX +v86intn.3: subl %edi,%esi # From + shrl $0x4,%edi # linear + movw %dx,-0x2(%ebx) # Save flags + movw %di,-0x4(%ebx) # Save CS + leal -0x6(%ebx),%ebx # Adjust SP + movw %si,(%ebx) # Save IP + shll $0x2,%eax # Scale + movzwl (%eax),%esi # Load IP + movzwl 0x2(%eax),%edi # Load CS + movl %edi,0x2c(%ebp) # Save CS + xorl %edi,%edi # No ESI adjustment + andb $~0x1,%dh # Clear TF + jmp v86mon.5 # Finish up +# +# Hardware interrupt jump table. +# +intx20: push $0x8 # Int 0x20: IRQ0 + jmp int_hw # V86 int 0x8 + push $0x9 # Int 0x21: IRQ1 + jmp int_hw # V86 int 0x9 + push $0xa # Int 0x22: IRQ2 + jmp int_hw # V86 int 0xa + push $0xb # Int 0x23: IRQ3 + jmp int_hw # V86 int 0xb + push $0xc # Int 0x24: IRQ4 + jmp int_hw # V86 int 0xc + push $0xd # Int 0x25: IRQ5 + jmp int_hw # V86 int 0xd + push $0xe # Int 0x26: IRQ6 + jmp int_hw # V86 int 0xe + push $0xf # Int 0x27: IRQ7 + jmp int_hw # V86 int 0xf + push $0x70 # Int 0x28: IRQ8 + jmp int_hw # V86 int 0x70 + push $0x71 # Int 0x29: IRQ9 + jmp int_hw # V86 int 0x71 + push $0x72 # Int 0x2a: IRQ10 + jmp int_hw # V86 int 0x72 + push $0x73 # Int 0x2b: IRQ11 + jmp int_hw # V86 int 0x73 + push $0x74 # Int 0x2c: IRQ12 + jmp int_hw # V86 int 0x74 + push $0x75 # Int 0x2d: IRQ13 + jmp int_hw # V86 int 0x75 + push $0x76 # Int 0x2e: IRQ14 + jmp int_hw # V86 int 0x76 + push $0x77 # Int 0x2f: IRQ15 + jmp int_hw # V86 int 0x77 +# +# Reflect hardware interrupts. +# +int_hw: testb $0x2,0xe(%esp,1) # V86 mode? + jz intusr # No + pushl $SEL_SDATA # Address + popl %ds # data + xchgl %eax,(%esp,1) # Swap EAX, int no + pushl %ebp # Address + movl %esp,%ebp # stack frame + pushl %ebx # Save + shll $0x2,%eax # Get int + movl (%eax),%eax # vector + subl $0x6,0x14(%ebp) # Adjust V86 ESP + movzwl 0x18(%ebp),%ebx # V86 SS + shll $0x4,%ebx # * 0x10 + addl 0x14(%ebp),%ebx # + V86 ESP + xchgw %ax,0x8(%ebp) # Swap V86 IP + rorl $0x10,%eax # Swap words + xchgw %ax,0xc(%ebp) # Swap V86 CS + roll $0x10,%eax # Swap words + movl %eax,(%ebx) # CS:IP for IRET + movl 0x10(%ebp),%eax # V86 flags + movw %ax,0x4(%ebx) # Flags for IRET + andb $~0x3,0x11(%ebp) # Clear IF, TF + popl %ebx # Restore + popl %ebp # saved + popl %eax # registers + iret # To V86 mode +# +# Invoke V86 interrupt from user mode, with arguments. +# +intx31: stc # Have btx_v86 + pushl %eax # Missing int no +# +# Invoke V86 interrupt from user mode. +# +intusr: std # String ops dec + pushl %eax # Expand + pushl %eax # stack + pushl %eax # frame + pusha # Save + pushl %gs # Save + movl %esp,%eax # seg regs + pushl %fs # and + pushl %ds # point + pushl %es # to them + push $SEL_SDATA # Set up + popl %ds # to + pushl %ds # address + popl %es # data + movl $MEM_USR,%ebx # User base + movl %ebx,%edx # address + jc intusr.1 # If btx_v86 + xorl %edx,%edx # Control flags + xorl %ebp,%ebp # btx_v86 pointer +intusr.1: leal 0x50(%esp,1),%esi # Base of frame + pushl %esi # Save + addl -0x4(%esi),%ebx # User ESP + movl MEM_TSS+TSS_ESP1,%edi # Link stack pointer + leal -0x4(%edi),%edi # Adjust for push + xorl %ecx,%ecx # Zero + movb $0x5,%cl # Push exception + rep # frame on + movsl # link stack + xchgl %eax,%esi # Saved seg regs + movl 0x40(%esp,1),%eax # Get int no + testl %edx,%edx # Have btx_v86? + jz intusr.2 # No + movl (%ebx),%ebp # btx_v86 pointer + movb $0x4,%cl # Count + addl %ecx,%ebx # Adjust for pop + rep # Push saved seg regs + movsl # on link stack + addl %ebp,%edx # Flatten btx_v86 ptr + leal 0x14(%edx),%esi # Seg regs pointer + movl 0x4(%edx),%eax # Get int no/address + movzwl 0x2(%edx),%edx # Get control flags +intusr.2: movl %ebp,(%edi) # Push btx_v86 and + movl %edi,MEM_TSS+TSS_ESP1 # save link stack ptr + popl %edi # Base of frame + xchgl %eax,%ebp # Save intno/address + movl 0x48(%esp,1),%eax # Get flags + testb $0x2,%dl # Simulate CALLF? + jnz intusr.3 # Yes + decl %ebx # Push flags + decl %ebx # on V86 + movw %ax,(%ebx) # stack +intusr.3: movb $0x4,%cl # Count + subl %ecx,%ebx # Push return address + movl $inthlt,(%ebx) # on V86 stack + rep # Copy seg regs to + movsl # exception frame + xchgl %eax,%ecx # Save flags + movl %ebx,%eax # User ESP + subl $V86_STK,%eax # Less bytes + ja intusr.4 # to + xorl %eax,%eax # keep +intusr.4: shrl $0x4,%eax # Gives segment + stosl # Set SS + shll $0x4,%eax # To bytes + xchgl %eax,%ebx # Swap + subl %ebx,%eax # Gives offset + stosl # Set ESP + xchgl %eax,%ecx # Get flags + btsl $0x11,%eax # Set VM + andb $~0x1,%ah # Clear TF + stosl # Set EFL + xchgl %eax,%ebp # Get int no/address + testb $0x1,%dl # Address? + jnz intusr.5 # Yes + shll $0x2,%eax # Scale + movl (%eax),%eax # Load int vector +intusr.5: movl %eax,%ecx # Save + shrl $0x10,%eax # Gives segment + stosl # Set CS + movw %cx,%ax # Restore + stosl # Set EIP + leal 0x10(%esp,1),%esp # Discard seg regs + popa # Restore + iret # To V86 mode +# +# System Call. +# +intx30: cmpl $SYS_EXEC,%eax # Exec system call? + jne intx30.1 # No + pushl %ss # Set up + popl %es # all + pushl %es # segment + popl %ds # registers + pushl %ds # for the + popl %fs # program + pushl %fs # we're + popl %gs # invoking + movl $MEM_USR,%eax # User base address + addl 0xc(%esp,1),%eax # Change to user + leal 0x4(%eax),%esp # stack +ifdef(`PAGING',` + movl %cr0,%eax # Turn + andl $~0x80000000,%eax # off + movl %eax,%cr0 # paging + xorl %eax,%eax # Flush + movl %eax,%cr3 # TLB +') + popl %eax # Call + call *%eax # program +intx30.1: incb %ss:btx_hdr+0x7 # Flag reboot + jmp exit # Exit +# +# Dump structure [EBX] to [EDI], using format string [ESI]. +# +dump.0: stosb # Save char +dump: lodsb # Load char + testb %al,%al # End of string? + jz dump.10 # Yes + testb $0x80,%al # Control? + jz dump.0 # No + movb %al,%ch # Save control + movb $'=',%al # Append + stosb # '=' + lodsb # Get offset + pushl %esi # Save + movsbl %al,%esi # To + addl %ebx,%esi # pointer + testb $DMP_X16,%ch # Dump word? + jz dump.1 # No + lodsw # Get and + call hex16 # dump it +dump.1: testb $DMP_X32,%ch # Dump long? + jz dump.2 # No + lodsl # Get and + call hex32 # dump it +dump.2: testb $DMP_MEM,%ch # Dump memory? + jz dump.8 # No + pushl %ds # Save + testb $0x2,0x52(%ebx) # V86 mode? + jnz dump.3 # Yes + verr 0x4(%esi) # Readable selector? + jnz dump.3 # No + ldsl (%esi),%esi # Load pointer + jmp dump.4 # Join common code +dump.3: lodsl # Set offset + xchgl %eax,%edx # Save + lodsl # Get segment + shll $0x4,%eax # * 0x10 + addl %edx,%eax # + offset + xchgl %eax,%esi # Set pointer +dump.4: movb $0x10,%cl # Bytes to dump +dump.5: lodsb # Get byte and + call hex8 # dump it + decb %cl # Keep count + jz dump.7 # If done + movb $'-',%al # Separator + cmpb $0x8,%cl # Half way? + je dump.6 # Yes + movb $' ',%al # Use space +dump.6: stosb # Save separator + jmp dump.5 # Continue +dump.7: popl %ds # Restore +dump.8: popl %esi # Restore + movb $0xa,%al # Line feed + testb $DMP_EOL,%ch # End of line? + jnz dump.9 # Yes + movb $' ',%al # Use spaces + stosb # Save one +dump.9: jmp dump.0 # Continue +dump.10: stosb # Terminate string + ret # To caller +# +# Convert EAX, AX, or AL to hex, saving the result to [EDI]. +# +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) +# +# Output zero-terminated string [ESI] to the console. +# +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jnz putstr.0 # No + ret # To caller +# +# Output character AL to the console. +# +putchr: pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $' ',%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore + ret # To caller + + .p2align 4 +# +# Global descriptor table. +# +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA + .word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE + .word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA + .word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS +gdt.1: +# +# Pseudo-descriptors. +# +gdtdesc: .word gdt.1-gdt-1,gdt,0x0 # GDT +idtdesc: .word _IDTLM,MEM_IDT,0x0 # IDT +ivtdesc: .word 0x400-0x0-1,0x0,0x0 # IVT +# +# IDT construction control string. +# +idtctl: .byte 0x10, 0x8e # Int 0x0-0xf + .word 0x7dfb,intx00 # (exceptions) + .byte 0x10, 0x8e # Int 0x10 + .word 0x1, intx10 # (exception) + .byte 0x10, 0x8e # Int 0x20-0x2f + .word 0xffff,intx20 # (hardware) + .byte 0x1, 0xee # int 0x30 + .word 0x1, intx30 # (system call) + .byte 0x2, 0xee # Int 0x31-0x32 + .word 0x1, intx31 # (V86, null) + .byte 0x0 # End of string +# +# Dump format string. +# +dmpfmt: .byte '\n' # "\n" + .ascii "int" # "int=" + .byte 0x80|DMP_X32, 0x40 # "00000000 " + .ascii "err" # "err=" + .byte 0x80|DMP_X32, 0x44 # "00000000 " + .ascii "efl" # "efl=" + .byte 0x80|DMP_X32, 0x50 # "00000000 " + .ascii "eip" # "eip=" + .byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n" + .ascii "eax" # "eax=" + .byte 0x80|DMP_X32, 0x34 # "00000000 " + .ascii "ebx" # "ebx=" + .byte 0x80|DMP_X32, 0x28 # "00000000 " + .ascii "ecx" # "ecx=" + .byte 0x80|DMP_X32, 0x30 # "00000000 " + .ascii "edx" # "edx=" + .byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n" + .ascii "esi" # "esi=" + .byte 0x80|DMP_X32, 0x1c # "00000000 " + .ascii "edi" # "edi=" + .byte 0x80|DMP_X32, 0x18 # "00000000 " + .ascii "ebp" # "ebp=" + .byte 0x80|DMP_X32, 0x20 # "00000000 " + .ascii "esp" # "esp=" + .byte 0x80|DMP_X32|DMP_EOL,0x0 # "00000000\n" + .ascii "cs" # "cs=" + .byte 0x80|DMP_X16, 0x4c # "0000 " + .ascii "ds" # "ds=" + .byte 0x80|DMP_X16, 0xc # "0000 " + .ascii "es" # "es=" + .byte 0x80|DMP_X16, 0x8 # "0000 " + .ascii " " # " " + .ascii "fs" # "fs=" + .byte 0x80|DMP_X16, 0x10 # "0000 " + .ascii "gs" # "gs=" + .byte 0x80|DMP_X16, 0x14 # "0000 " + .ascii "ss" # "ss=" + .byte 0x80|DMP_X16|DMP_EOL,0x4 # "0000\n" + .ascii "cs:eip" # "cs:eip=" + .byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n" + .ascii "ss:esp" # "ss:esp=" + .byte 0x80|DMP_MEM|DMP_EOL,0x0 # "00 00 ... 00 00\n" + .asciz "BTX halted" # End +# +# End of BTX memory. +# + .p2align 4 +break: diff --git a/src/sys/boot/btx/btxldr/Makefile b/src/sys/boot/btx/btxldr/Makefile new file mode 100755 index 0000000..d421cd5 --- /dev/null +++ b/src/sys/boot/btx/btxldr/Makefile @@ -0,0 +1,28 @@ +# $FreeBSD: src/sys/boot/i386/btx/btxldr/Makefile,v 1.7.2.1 2000/04/15 03:09:41 ps Exp $ + +M4?= m4 +M4FLAGS+= -DLOADER_ADDRESS=${LOADER_ADDRESS} + +.if defined(BTXLDR_VERBOSE) +M4FLAGS+= -DBTXLDR_VERBOSE +.endif + +all: btxldr + +btxldr: btxldr.o +.if ${OBJFORMAT} == aout + ${LD} -nostdlib -N -s -T ${LOADER_ADDRESS} -o btxldr.out btxldr.o + dd if=btxldr.out of=${.TARGET} ibs=32 skip=1 +.else + ${LD} -N -e start -Ttext ${LOADER_ADDRESS} -o btxldr.out btxldr.o + objcopy -S -O binary btxldr.out ${.TARGET} +.endif + +btxldr.o: btxldr.s + (cd ${.CURDIR}; ${M4} ${M4FLAGS} btxldr.s ) | \ + ${AS} ${AFLAGS} -o ${.TARGET} + +CLEANFILES+= btxldr btxldr.out btxldr.o + +.include <${.CURDIR}/../../Makefile.inc> +.include diff --git a/src/sys/boot/btx/btxldr/btxldr.s b/src/sys/boot/btx/btxldr/btxldr.s new file mode 100755 index 0000000..3604c5d --- /dev/null +++ b/src/sys/boot/btx/btxldr/btxldr.s @@ -0,0 +1,396 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/btxldr/btxldr.s,v 1.8.2.2 2000/07/06 23:04:29 obrien Exp $ + +# +# Prototype BTX loader program, written in a couple of hours. The +# real thing should probably be more flexible, and in C. +# + +# +# Memory locations. +# + .set MEM_STUB,0x600 # Real mode stub + .set MEM_ESP,0x1000 # New stack pointer + .set MEM_TBL,0x5000 # BTX page tables + .set MEM_ENTRY,0x9010 # BTX entry point + .set MEM_DATA,start+0x1000 # Data segment +# +# Segment selectors. +# + .set SEL_SCODE,0x8 # 4GB code + .set SEL_SDATA,0x10 # 4GB data + .set SEL_RCODE,0x18 # 64K code + .set SEL_RDATA,0x20 # 64K data +# +# Paging constants. +# + .set PAG_SIZ,0x1000 # Page size + .set PAG_ENT,0x4 # Page entry size +# +# Screen constants. +# + .set SCR_MAT,0x7 # Mode/attribute + .set SCR_COL,0x50 # Columns per row + .set SCR_ROW,0x19 # Rows per screen +# +# BIOS Data Area locations. +# + .set BDA_MEM,0x413 # Free memory + .set BDA_SCR,0x449 # Video mode + .set BDA_POS,0x450 # Cursor position +# +# Required by aout gas inadequacy. +# + .set SIZ_STUB,0x1a # Size of stub +# +# We expect to be loaded by boot2 at the origin defined in ./Makefile. +# + .globl start +# +# BTX program loader for ELF clients. +# +start: cld # String ops inc + movl $m_logo,%esi # Identify + call putstr # ourselves + movzwl BDA_MEM,%eax # Get base memory + shll $0xa,%eax # in bytes + movl %eax,%ebp # Base of user stack +ifdef(`BTXLDR_VERBOSE',` + movl $m_mem,%esi # Display + call hexout # amount of + call putstr # base memory +') + lgdt gdtdesc # Load new GDT +# +# Relocate caller's arguments. +# +ifdef('BTXLDR_VERBOSE',` + movl $m_esp,%esi # Display + movl %esp,%eax # caller + call hexout # stack + call putstr # pointer + movl $m_args,%esi # Format string + leal 0x4(%esp,1),%ebx # First argument + movl $0x6,%ecx # Count +start.1: movl (%ebx),%eax # Get argument and + addl $0x4,%ebx # bump pointer + call hexout # Display it + loop start.1 # Till done + call putstr # End message +') + movl $0x48,%ecx # Allocate space + subl %ecx,%ebp # for bootinfo + movl 0x18(%esp,1),%esi # Source: bootinfo + cmpl $0x0, %esi # If the bootinfo pointer + je start_null_bi # is null, don't copy it + movl %ebp,%edi # Destination + rep # Copy + movsb # it + movl %ebp,0x18(%esp,1) # Update pointer +ifdef(`BTXLDR_VERBOSE',` + movl $m_rel_bi,%esi # Display + movl %ebp,%eax # bootinfo + call hexout # relocation + call putstr # message +') +start_null_bi: movl $0x18,%ecx # Allocate space + subl %ecx,%ebp # for arguments + leal 0x4(%esp,1),%esi # Source + movl %ebp,%edi # Destination + rep # Copy + movsb # them +ifdef(`BTXLDR_VERBOSE',` + movl $m_rel_args,%esi # Display + movl %ebp,%eax # argument + call hexout # relocation + call putstr # message +') +# +# Set up BTX kernel. +# + movl $MEM_ESP,%esp # Set up new stack + movl $MEM_DATA,%ebx # Data segment + movl $m_vers,%esi # Display BTX + call putstr # version message + movb 0x5(%ebx),%al # Get major version + addb $'0',%al # Display + call putchr # it + movb $'.',%al # And a + call putchr # dot + movb 0x6(%ebx),%al # Get minor + xorb %ah,%ah # version + movb $0xa,%dl # Divide + divb %dl,%al # by 10 + addb $'0',%al # Display + call putchr # tens + movb %ah,%al # Get units + addb $'0',%al # Display + call putchr # units + call putstr # End message + movl %ebx,%esi # BTX image + movzwl 0x8(%ebx),%edi # Compute + orl $PAG_SIZ/PAG_ENT-1,%edi # the + incl %edi # BTX + shll $0x2,%edi # load + addl $MEM_TBL,%edi # address + pushl %edi # Save load address + movzwl 0xa(%ebx),%ecx # Image size +ifdef(`BTXLDR_VERBOSE',` + pushl %ecx # Save image size +') + rep # Relocate + movsb # BTX + movl %esi,%ebx # Keep place +ifdef(`BTXLDR_VERBOSE',` + movl $m_rel_btx,%esi # Restore + popl %eax # parameters + call hexout # and +') + popl %ebp # display +ifdef(`BTXLDR_VERBOSE',` + movl %ebp,%eax # the + call hexout # relocation + call putstr # message +') + addl $PAG_SIZ,%ebp # Display +ifdef(`BTXLDR_VERBOSE',` + movl $m_base,%esi # the + movl %ebp,%eax # user + call hexout # base + call putstr # address +') +# +# Set up ELF-format client program. +# + cmpl $0x464c457f,(%ebx) # ELF magic number? + je start.3 # Yes + movl $e_fmt,%esi # Display error + call putstr # message +start.2: jmp start.2 # Hang +start.3: +ifdef(`BTXLDR_VERBOSE',` + movl $m_elf,%esi # Display ELF + call putstr # message + movl $m_segs,%esi # Format string +') + movl $0x2,%edi # Segment count + movl 0x1c(%ebx),%edx # Get e_phoff + addl %ebx,%edx # To pointer + movzwl 0x2c(%ebx),%ecx # Get e_phnum +start.4: cmpl $0x1,(%edx) # Is p_type PT_LOAD? + jne start.6 # No +ifdef(`BTXLDR_VERBOSE',` + movl 0x4(%edx),%eax # Display + call hexout # p_offset + movl 0x8(%edx),%eax # Display + call hexout # p_vaddr + movl 0x10(%edx),%eax # Display + call hexout # p_filesz + movl 0x14(%edx),%eax # Display + call hexout # p_memsz + call putstr # End message +') + pushl %esi # Save + pushl %edi # working + pushl %ecx # registers + movl 0x4(%edx),%esi # Get p_offset + addl %ebx,%esi # as pointer + movl 0x8(%edx),%edi # Get p_vaddr + addl %ebp,%edi # as pointer + movl 0x10(%edx),%ecx # Get p_filesz + rep # Set up + movsb # segment + movl 0x14(%edx),%ecx # Any bytes + subl 0x10(%edx),%ecx # to zero? + jz start.5 # No + xorb %al,%al # Then + rep # zero + stosb # them +start.5: popl %ecx # Restore + popl %edi # working + popl %esi # registers + decl %edi # Segments to do + je start.7 # If none +start.6: addl $0x20,%edx # To next entry + loop start.4 # Till done +start.7: +ifdef(`BTXLDR_VERBOSE',` + movl $m_done,%esi # Display done + call putstr # message +') + movl $start.8,%esi # Real mode stub + movl $MEM_STUB,%edi # Destination + movl $start.9-start.8,%ecx # Size + rep # Relocate + movsb # it + ljmp $SEL_RCODE,$MEM_STUB # To 16-bit code + .code16 +start.8: xorw %ax,%ax # Data + movb $SEL_RDATA,%al # selector + movw %ax,%ss # Reload SS + movw %ax,%ds # Reset + movw %ax,%es # other + movw %ax,%fs # segment + movw %ax,%gs # limits + movl %cr0,%eax # Switch to + decw %ax # real + movl %eax,%cr0 # mode + ljmp $0,$MEM_ENTRY # Jump to BTX entry point +start.9: + .code32 +# +# Output message [ESI] followed by EAX in hex. +# +hexout: pushl %eax # Save + call putstr # Display message + popl %eax # Restore + pushl %esi # Save + pushl %edi # caller's + movl $buf,%edi # Buffer + pushl %edi # Save + call hex32 # To hex + xorb %al,%al # Terminate + stosb # string + popl %esi # Restore +hexout.1: lodsb # Get a char + cmpb $'0',%al # Leading zero? + je hexout.1 # Yes + testb %al,%al # End of string? + jne hexout.2 # No + decl %esi # Undo +hexout.2: decl %esi # Adjust for inc + call putstr # Display hex + popl %edi # Restore + popl %esi # caller's + ret # To caller +# +# Output zero-terminated string [ESI] to the console. +# +putstr.0: call putchr # Output char +putstr: lodsb # Load char + testb %al,%al # End of string? + jne putstr.0 # No + ret # To caller +# +# Output character AL to the console. +# +putchr: pusha # Save + xorl %ecx,%ecx # Zero for loops + movb $SCR_MAT,%ah # Mode/attribute + movl $BDA_POS,%ebx # BDA pointer + movw (%ebx),%dx # Cursor position + movl $0xb8000,%edi # Regen buffer (color) + cmpb %ah,BDA_SCR-BDA_POS(%ebx) # Mono mode? + jne putchr.1 # No + xorw %di,%di # Regen buffer (mono) +putchr.1: cmpb $0xa,%al # New line? + je putchr.2 # Yes + xchgl %eax,%ecx # Save char + movb $SCR_COL,%al # Columns per row + mulb %dh # * row position + addb %dl,%al # + column + adcb $0x0,%ah # position + shll %eax # * 2 + xchgl %eax,%ecx # Swap char, offset + movw %ax,(%edi,%ecx,1) # Write attr:char + incl %edx # Bump cursor + cmpb $SCR_COL,%dl # Beyond row? + jb putchr.3 # No +putchr.2: xorb %dl,%dl # Zero column + incb %dh # Bump row +putchr.3: cmpb $SCR_ROW,%dh # Beyond screen? + jb putchr.4 # No + leal 2*SCR_COL(%edi),%esi # New top line + movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move + rep # Scroll + movsl # screen + movb $' ',%al # Space + movb $SCR_COL,%cl # Columns to clear + rep # Clear + stosw # line + movb $SCR_ROW-1,%dh # Bottom line +putchr.4: movw %dx,(%ebx) # Update position + popa # Restore + ret # To caller +# +# Convert EAX, AX, or AL to hex, saving the result to [EDI]. +# +hex32: pushl %eax # Save + shrl $0x10,%eax # Do upper + call hex16 # 16 + popl %eax # Restore +hex16: call hex16.1 # Do upper 8 +hex16.1: xchgb %ah,%al # Save/restore +hex8: pushl %eax # Save + shrb $0x4,%al # Do upper + call hex8.1 # 4 + popl %eax # Restore +hex8.1: andb $0xf,%al # Get lower 4 + cmpb $0xa,%al # Convert + sbbb $0x69,%al # to hex + das # digit + orb $0x20,%al # To lower case + stosb # Save char + ret # (Recursive) + + .data + .p2align 4 +# +# Global descriptor table. +# +gdt: .word 0x0,0x0,0x0,0x0 # Null entry + .word 0xffff,0x0,0x9a00,0xcf # SEL_SCODE + .word 0xffff,0x0,0x9200,0xcf # SEL_SDATA + .word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE + .word 0xffff,0x0,0x9200,0x0 # SEL_RDATA +gdt.1: +gdtdesc: .word gdt.1-gdt-1 # Limit + .long gdt # Base +# +# Messages. +# +m_logo: .asciz " \nBTX loader 1.00 " +m_vers: .asciz "BTX version is \0\n" +e_fmt: .asciz "Error: Client format not supported\n" +ifdef(`BTXLDR_VERBOSE',` +m_mem: .asciz "Starting in protected mode (base mem=\0)\n" +m_esp: .asciz "Arguments passed (esp=\0):\n" +m_args: .asciz"\n" +m_rel_bi: .asciz "Relocated bootinfo (size=48) to \0\n" +m_rel_args: .asciz "Relocated arguments (size=18) to \0\n" +m_rel_btx: .asciz "Relocated kernel (size=\0) to \0\n" +m_base: .asciz "Client base address is \0\n" +m_elf: .asciz "Client format is ELF\n" +m_segs: .asciz "text segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" + .asciz "data segment: offset=" + .asciz " vaddr=" + .asciz " filesz=" + .asciz " memsz=\0\n" +m_done: .asciz "Loading complete\n" +') +# +# Uninitialized data area. +# +buf: # Scratch buffer diff --git a/src/sys/boot/btx/lib/Makefile b/src/sys/boot/btx/lib/Makefile new file mode 100755 index 0000000..c993e57 --- /dev/null +++ b/src/sys/boot/btx/lib/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD: src/sys/boot/i386/btx/lib/Makefile,v 1.3.2.1 2002/07/19 18:46:28 ru Exp $ + +OBJS= btxcsu.o btxsys.o btxv86.o +AFLAGS+= -elf +LDFLAGS+= -elf +CLEANFILES+= crt0.o ${OBJS} + +all: crt0.o + +crt0.o: ${OBJS} + ${LD} ${LDFLAGS} -i -o ${.TARGET} ${OBJS} + +.include + +.s.o: + ${AS} ${AFLAGS} -o ${.TARGET} ${.IMPSRC} diff --git a/src/sys/boot/btx/lib/btxcsu.s b/src/sys/boot/btx/lib/btxcsu.s new file mode 100755 index 0000000..119fda6 --- /dev/null +++ b/src/sys/boot/btx/lib/btxcsu.s @@ -0,0 +1,43 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxcsu.s,v 1.3 1999/08/28 00:40:07 peter Exp $ + +# +# BTX C startup code (ELF). +# + +# +# Globals. +# + .global _start +# +# Constants. +# + .set ARGADJ,0xfa0 # Argument adjustment +# +# Client entry point. +# +_start: movl %eax,__base # Set base address + movl %esp,%eax # Set + addl $ARGADJ,%eax # argument + movl %eax,__args # pointer + call main # Invoke client main() + call exit # Invoke client exit() +# +# Data. +# + .comm __base,4 # Client base address + .comm __args,4 # Client arguments diff --git a/src/sys/boot/btx/lib/btxsys.s b/src/sys/boot/btx/lib/btxsys.s new file mode 100755 index 0000000..6bca740 --- /dev/null +++ b/src/sys/boot/btx/lib/btxsys.s @@ -0,0 +1,40 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxsys.s,v 1.2 1999/08/28 00:40:07 peter Exp $ + +# +# BTX system calls. +# + +# +# Globals. +# + .global __exit + .global __exec +# +# Constants. +# + .set INT_SYS,0x30 # Interrupt number +# +# System call: exit +# +__exit: xorl %eax,%eax # BTX system + int $INT_SYS # call 0x0 +# +# System call: exec +# +__exec: movl $0x1,%eax # BTX system + int $INT_SYS # call 0x1 diff --git a/src/sys/boot/btx/lib/btxv86.h b/src/sys/boot/btx/lib/btxv86.h new file mode 100755 index 0000000..1ef0712 --- /dev/null +++ b/src/sys/boot/btx/lib/btxv86.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1998 Robert Nordier + * All rights reserved. + * + * Redistribution and use in source and binary forms are freely + * permitted provided that the above copyright notice and this + * paragraph and the following disclaimer are duplicated in all + * such forms. + * + * This software is provided "AS IS" and without any express or + * implied warranties, including, without limitation, the implied + * warranties of merchantability and fitness for a particular + * purpose. + */ + +/* + * $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.h,v 1.5 1999/08/28 00:40:08 peter Exp $ + */ + +#ifndef _BTXV86_H_ +#define _BTXV86_H_ + +#include + +#define V86_ADDR 0x10000 /* Segment:offset address */ +#define V86_CALLF 0x20000 /* Emulate far call */ +#define V86_FLAGS 0x40000 /* Return flags */ + +struct __v86 { + uint32_t ctl; /* Control flags */ + uint32_t addr; /* Interrupt number or address */ + uint32_t es; /* V86 ES register */ + uint32_t ds; /* V86 DS register */ + uint32_t fs; /* V86 FS register */ + uint32_t gs; /* V86 GS register */ + uint32_t eax; /* V86 EAX register */ + uint32_t ecx; /* V86 ECX register */ + uint32_t edx; /* V86 EDX register */ + uint32_t ebx; /* V86 EBX register */ + uint32_t efl; /* V86 eflags register */ + uint32_t ebp; /* V86 EBP register */ + uint32_t esi; /* V86 ESI register */ + uint32_t edi; /* V86 EDI register */ +}; + +extern struct __v86 __v86; /* V86 interface structure */ +void __v86int(void); + +#define v86 __v86 +#define v86int __v86int + +extern u_int32_t __base; +extern u_int32_t __args; + +#define PTOV(pa) ((caddr_t)(pa) - __base) +#define VTOP(va) ((vm_offset_t)(va) + __base) +#define VTOPSEG(va) (u_int16_t)(VTOP((caddr_t)va) >> 4) +#define VTOPOFF(va) (u_int16_t)(VTOP((caddr_t)va) & 0xf) + +void __exit(int) __attribute__((__noreturn__)); +void __exec(caddr_t, ...); + +#endif /* !_BTXV86_H_ */ diff --git a/src/sys/boot/btx/lib/btxv86.s b/src/sys/boot/btx/lib/btxv86.s new file mode 100755 index 0000000..6d6af19 --- /dev/null +++ b/src/sys/boot/btx/lib/btxv86.s @@ -0,0 +1,85 @@ +# +# Copyright (c) 1998 Robert Nordier +# All rights reserved. +# +# Redistribution and use in source and binary forms are freely +# permitted provided that the above copyright notice and this +# paragraph and the following disclaimer are duplicated in all +# such forms. +# +# This software is provided "AS IS" and without any express or +# implied warranties, including, without limitation, the implied +# warranties of merchantability and fitness for a particular +# purpose. +# + +# $FreeBSD: src/sys/boot/i386/btx/lib/btxv86.s,v 1.3 1999/08/28 00:40:08 peter Exp $ + +# +# BTX V86 interface. +# + +# +# Globals. +# + .global __v86int +# +# Fields in V86 interface structure. +# + .set V86_CTL,0x0 # Control flags + .set V86_ADDR,0x4 # Int number/address + .set V86_ES,0x8 # V86 ES + .set V86_DS,0xc # V86 DS + .set V86_FS,0x10 # V86 FS + .set V86_GS,0x14 # V86 GS + .set V86_EAX,0x18 # V86 EAX + .set V86_ECX,0x1c # V86 ECX + .set V86_EDX,0x20 # V86 EDX + .set V86_EBX,0x24 # V86 EBX + .set V86_EFL,0x28 # V86 eflags + .set V86_EBP,0x2c # V86 EBP + .set V86_ESI,0x30 # V86 ESI + .set V86_EDI,0x34 # V86 EDI +# +# Other constants. +# + .set INT_V86,0x31 # Interrupt number + .set SIZ_V86,0x38 # Size of V86 structure +# +# V86 interface function. +# +__v86int: popl __v86ret # Save return address + pushl $__v86 # Push pointer + call __v86_swap # Load V86 registers + int $INT_V86 # To BTX + call __v86_swap # Load user registers + addl $0x4,%esp # Discard pointer + pushl __v86ret # Restore return address + ret # To user +# +# Swap V86 and user registers. +# +__v86_swap: xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + xchgl %eax,V86_EAX(%ebp) # Swap EAX + xchgl %ecx,V86_ECX(%ebp) # Swap ECX + xchgl %edx,V86_EDX(%ebp) # Swap EDX + xchgl %ebx,V86_EBX(%ebp) # Swap EBX + pushl %eax # Save + pushf # Put eflags + popl %eax # in EAX + xchgl %eax,V86_EFL(%ebp) # Swap + pushl %eax # Put EAX + popf # in eflags + movl 0x8(%esp,1),%eax # Load EBP + xchgl %eax,V86_EBP(%ebp) # Swap + movl %eax,0x8(%esp,1) # Save EBP + popl %eax # Restore + xchgl %esi,V86_ESI(%ebp) # Swap ESI + xchgl %edi,V86_EDI(%ebp) # Swap EDI + xchgl %ebp,0x4(%esp,1) # Swap pointer, EBP + ret # To caller +# +# V86 interface structure. +# + .comm __v86,SIZ_V86 + .comm __v86ret,4 diff --git a/src/sys/init/main.c b/src/sys/init/main.c index c8f947d..6167979 100755 --- a/src/sys/init/main.c +++ b/src/sys/init/main.c @@ -115,6 +115,7 @@ int main(); void _start(void) { + asm("cli"); asm( "lgdtl (loadGdt) \n" "movw $0x10,%ax \n" diff --git a/src/tools/format.c b/src/tools/format.c index 97e6a29..5a043f7 100755 --- a/src/tools/format.c +++ b/src/tools/format.c @@ -108,6 +108,12 @@ rewind(driveFd); fseek(driveFd,(startSector * 512),0); if (fwrite(BAT,batSize,1,driveFd) >= 1) { + printf("size [%i]\n",partInfo->size); + printf("startSector: [%i]\n",partInfo->startSector); + printf("bat: [%i]\n",partInfo->blockAllocationTable); + printf("rootDir: [%i]\n",partInfo->rootDirectory); + printf("sizeof: [%i]\n",sizeof(struct blockAllocationTableEntry)); + printf("size: [%i]\n",(size/4096)); printf("Formatted!\n"); } else { diff --git a/ubixos.kdevprj b/ubixos.kdevprj index c617797..bac4546 100755 --- a/ubixos.kdevprj +++ b/ubixos.kdevprj @@ -566,10 +566,16 @@ type=DATA [src/sys/boot/Makefile.am] -files=src/sys/boot/Makefile,src/sys/boot/bootsec.asm +files=src/sys/boot/Makefile,src/sys/boot/bootsec.asm,src/sys/boot/boot.asm sub_dirs= type=normal +[src/sys/boot/boot.asm] +dist=true +install=false +install_location= +type=SOURCE + [src/sys/boot/bootsec.asm] dist=true install=false