commit f397c4797c524c11817f2c0fadd3ba8cbad3d34f Author: erich Date: Wed Sep 18 02:15:52 1996 +0000 Initial revision diff --git a/shared_src/asm.S b/shared_src/asm.S new file mode 100644 index 000000000..12907b0d2 --- /dev/null +++ b/shared_src/asm.S @@ -0,0 +1,1580 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define ASM_FILE + +#include "shared.h" + + .file "asm.S" + + .text + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + +ENTRY(start) + /* + * "start" should be loaded at 0x0:$STARTADDR. This next + * is to guarantee that. + */ + + /* ljmp $0, $codestart */ + .byte 0xea + .word 0x8070, 0 + + /* padding */ + .byte 0 + + /* + * Compatibility version number + * + * These MUST be at byte offset 6 and 7 of the executable + * + * DO NOT MOVE !!! + */ + .byte COMPAT_VERSION_MAJOR, COMPAT_VERSION_MINOR + + /* + * This is a special data area 8 bytes from the beginning. + */ + + . = EXT_C(start) + 0x8 + +VARIABLE(install_partition) + .long 0xFF00FF +VARIABLE(version_string) + .string "0.4" +VARIABLE(config_file) +#ifndef CONFIG_FILE_ASM + .string "/boot/grub/menu.lst" +#else /* CONFIG_FILE_ASM */ + CONFIG_FILE_ASM +#endif /* CONFIG_FILE_ASM */ + + /* + * Leave some breathing room for the config file name. + */ + + . = EXT_C(start) + 0x70 + +/* the code continues... */ +codestart: + /* set up %ds, %ss, and %es */ + xorw %ax, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* set up the real mode/BIOS stack */ + movl $STACKOFF, %esp + movl $STACKOFF, %ebp + + /* save boot drive reference */ + movb %dl, EXT_C(boot_drive) + + /* reset disk system (%ah = 0) */ + int $13 + + /* transition to protected mode */ + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + /* + * Call the start of main body of C code, which does some + * of it's own initialization before transferring to "cmain". + */ + call EXT_C(init_bios_info) + + +/* + * This call is special... it never returns... in fact it should simply + * hang at this point! + */ + +ENTRY(stop) + call EXT_C(prot_to_real) + + /* + * This next part is sort of evil. It takes advantage of the + * byte ordering on the x86 to work in either 16-bit or 32-bit + * mode, so think about it before changing it. + */ + +ENTRY(hard_stop) + hlt + jmp EXT_C(hard_stop) + +/* + * chain_stage1(segment, offset, part_table_addr) + * + * This starts another stage1 loader, at segment:offset. + */ + +ENTRY(chain_stage1) + /* no need to save anything, just use %esp */ + + /* store %ESI, presuming %ES is 0 */ + movl 0xc(%esp), %esi + + /* store new offset */ + movl 0x8(%esp), %eax + movl %eax, offset + + /* store new segment */ + movw 0x4(%esp), %ax + movw %ax, segment + + /* set up to pass boot drive */ + movb EXT_C(boot_drive), %dl + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + ljmp (offset) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + +/* + * chain_stage2(segment, offset) + * + * This starts another stage2 loader, at segment:offset. It presumes + * that the other one starts with this same "asm.S" file, and passes + * parameters by writing the embedded install variables. + */ + +ENTRY(chain_stage2) + /* no need to save anything, just use %esp */ + + /* store new offset */ + movl 0x8(%esp), %eax + movl %eax, offset + movl %eax, %ebx + + /* store new segment */ + movw 0x4(%esp), %ax + movw %ax, segment + shll $4, %eax + + /* generate linear address */ + addl %eax, %ebx + + /* store install info */ + movl EXT_C(install_partition), %eax + movl %eax, EXT_C(install_partition)-EXT_C(start)(%ebx) + + /* set up to pass boot drive */ + movb EXT_C(boot_drive), %dl + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + ljmp (offset) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + +/* + * These next two routines, "real_to_prot" and "prot_to_real" are structured + * in a very specific way. Be very careful when changing them. + * + * NOTE: Use of either one messes up %eax and %ebp. + */ + +ENTRY(real_to_prot) + cli + + /* load the GDT register */ + addr32 + data32 + lgdt gdtdesc + + /* turn on protected mode */ + movl %cr0, %eax + data32 + orl $CR0_PE_ON, %eax + movl %eax, %cr0 + + /* jump to relocation, flush prefetch queue, and reload %cs */ + data32 + ljmp $PROT_MODE_CSEG, $protcseg + +protcseg: + /* reload other segment registers */ + movw $PROT_MODE_DSEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* put the return address in a known safe location */ + movl (%esp), %eax + movl %eax, STACKOFF + + /* get protected mode stack */ + movl protstack, %eax + movl %eax, %esp + movl %eax, %ebp + + /* get return address onto the right stack */ + movl STACKOFF, %eax + movl %eax, (%esp) + + /* zero %eax */ + xorl %eax, %eax + + /* return on the old (or initialized) stack! */ + ret + + +ENTRY(prot_to_real) + /* just in case, set GDT */ + lgdt gdtdesc + + /* save the protected mode stack */ + movl %esp, %eax + movl %eax, protstack + + /* get the return address */ + movl (%esp), %eax + movl %eax, STACKOFF + + /* set up new stack */ + movl $STACKOFF, %eax + movl %eax, %esp + movl %eax, %ebp + + /* set up segment limits */ + movw $PSEUDO_RM_DSEG, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* this might be an extra step */ + ljmp $PSEUDO_RM_CSEG, $tmpcseg /* jump to a 16 bit segment */ + +tmpcseg: + /* clear the PE bit of CR0 */ + movl %cr0, %eax + data32 + andl $CR0_PE_OFF, %eax + movl %eax, %cr0 + + /* flush prefetch queue, reload %cs */ + data32 + ljmp $0, $realcseg + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + +realcseg: + /* we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + /* zero %eax */ + xorl %eax, %eax + + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* restore interrupts */ + sti + + /* return on new stack! */ + ret + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + +/* + * biosdisk(subfunc, drive, geometry, sector, nsec, segment) + * Read/write "nsec" sectors from disk to real segment "segment" + * offset zero + * + * If it will fit into the BIOS geometry, it tries the INT 0x13 + * AH= interface, else if it is a hard disk, it will + * try the hard disk LBA calls (not yet implemented). If these + * won't work, or otherwise it is out of the translated area, then + * it returns BIOS_GEOMETRY_ERROR. + */ + +ENTRY(biosdisk) + push %ebp + mov %esp, %ebp + + push %ebx + push %ecx + push %edx + push %esi + + /* + * "geometry" is a longword representing the BIOS geometry: + * 6 bit zero + * 10 bit cylinder (bytes 2 & 3) + * 8 bit head (byte 1) + * 8 bit sector (byte 0) + */ + + /* set up original sector number */ + xorl %edx, %edx + movl 0x14(%ebp), %eax + + /* get sector offset, place in %ecx */ + xorl %ebx, %ebx + movb 0x10(%ebp), %bl + divl %ebx + movl %edx, %ecx + + /* get track offset (head number) in %edx, + and cylinder offset in %eax */ + xorl %edx, %edx + xorl %ebx, %ebx + movb 0x11(%ebp), %bl + inc %ebx + divl %ebx + + /* check cylinder offset, is there a geometry problem here? */ + movl 0x10(%ebp), %ebx + shrl $16, %ebx + cmpl %ebx, %eax + + /* if not, go onto standard read function */ + jle disk_use_standard_bios + + /* XXX else we better use LBA or generate a geometry error */ + movl $BIOSDISK_ERROR_GEOMETRY, %eax + jmp disk_exit_32 + + /* + * This portion implements the BIOS standardized + * INT 0x13/AH= interface. + */ +disk_use_standard_bios: + + shll $8, %edx /* get head number to %dh */ + xchgl %eax, %ecx /* cylinder to %cx, sector to %al */ + /* cylinder; the highest 2 bits of cyl is in %cl */ + xchgb %ch, %cl + rorb $2, %cl + incb %al /* sector; sec starts from 1, not 0 */ + orb %al, %cl + movb 0xc(%ebp), %dl /* drive */ + + /* prot_to_real will set %es to 0, so must set it ourselves + after it is called */ + movb 0x18(%ebp), %bl /* number of sectors */ + movb 0x8(%ebp), %bh /* bios disk subfunction */ + shll $16, %ebx /* shift num sect. and subfunction */ + movw 0x1c(%ebp), %bx /* segment */ + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movw %bx, %es /* load segment */ + /* + * Shift num sectors and subfunction back + */ + shrl $16, %ebx + pushw %bx /* save num sectors */ + xorw %bx, %bx + + movw $3, %si + +disk_loop: + popw %ax /* restore num sectors */ + pushw %ax /* save num sectors */ + + /* BIOS call for reading/writing */ + int $0x13 + + /* set success return value */ + movb $0, %bl + + /* did we actually succeed? */ + jnc disk_exit_16 + + /* do we try again? */ + decw %si + cmpw $0, %si + + /* if this isn't the third try, go again */ + jne disk_loop + + /* save return value */ + movb %ah, %bl + +disk_exit_16: + call EXT_C(real_to_prot) /* back to protected mode */ + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movb %bl, %al /* return value in %eax */ + +disk_exit_32: + pop %esi + pop %edx + pop %ecx + pop %ebx + pop %ebp + + ret + + +/* + * + * get_diskinfo(drive): return a word that represents the + * max number of sectors and heads and cylinders for this drive + * + */ + +ENTRY(get_diskinfo) + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %ecx + pushl %edx + pushl %edi + pushl %esi + + movw 0x8(%ebp), %dx /* diskinfo(drive #) */ + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb %dl, %al + andb $0x80, %al + jnz hard_drive + +/* + * Perform floppy probe! + */ + + movl $probe_values-1, %esi + +probe_loop: + /* reset floppy controller INT 13h AH=0 */ + xorw %ax, %ax + int $0x13 + + incw %si + + /* movb (%si), %cl */ + .byte 0x8A, 0x0C + + /* if number of sectors is 0, display error and die */ + cmpb $0, %cl + + je probe_failed + + /* perform read */ + movw $SCRATCHSEG, %ax + movw %ax, %es + xorw %bx, %bx + movw $0x201, %ax + movb $0, %ch + movb $0, %dh + int $0x13 + + jc probe_loop + + /* %cl is already the correct value! */ + movb $1, %dh + movb $79, %ch + + jmp probe_success + +probe_values: + .byte 36, 18, 15, 9, 0 + +hard_drive: + movb $0x8, %ah /* ask for disk info */ + int $0x13 + + jc probe_failed + + /* es:di = parameter table */ + /* carry = 0 */ + +probe_success: + /* + * form a longword representing all this gunk: + * 6 bit zero + * 10 bit cylinder + * 8 bit head + * 8 bit sector + */ + movb %cl, %al /* Upper two bits of cylinder count */ + andl $192,%eax + leal 0(,%eax,4),%eax /* << 2 */ + movb %ch, %al /* Lower 8 bits */ + sall $16,%eax /* << 16 */ + movb %dh, %ah /* max head */ + andb $0x3f, %cl /* mask of cylinder gunk */ + movb %cl, %al /* max sector (and # sectors) */ + + movl %eax, %ebx /* save return value */ + jmp got_drive + +probe_failed: + /* + * Urk. Call failed. It is not supported for floppies by old + * BIOSes, but it should work for all hard drives!! + * + * Return a 0 here... presume there is no drive present. ???? + */ + + movl $0, %ebx /* not present value */ + +got_drive: + call EXT_C(real_to_prot) /* back to protected mode */ + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + /* set up return in correct register */ + movl %ebx, %eax + + popl %esi + popl %edi + popl %edx + popl %ecx + popl %ebx + popl %ebp + + ret + + +/* + * putchar(c) : Puts character on the screen, interpreting '\n' as in the + * UNIX fashion. + * + * BIOS call "INT 10H Function 0Eh" to write character to console + * Call with %ah = 0x0e + * %al = character + * %bh = page + * %bl = foreground color ( graphics modes) + */ + + +ENTRY(putchar) + push %ebp + push %eax + push %ebx + + movl 0x10(%esp), %bl + + /* if not '\n', just print the character */ + cmpb $0xa, %bl + jne pc_notnewline + + /* if newline, print CR as well */ + pushl $0xd + call EXT_C(putchar) + popl %eax + +pc_notnewline: + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb %bl, %al + movb $0xe, %ah + movw $1, %bx + int $0x10 + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + pop %ebx + pop %eax + pop %ebp + ret + + +/* + * + * get_memsize(i) : return the memory size in KB. i == 0 for conventional + * memory, i == 1 for extended memory + * BIOS call "INT 12H" to get conventional memory size + * BIOS call "INT 15H, AH=88H" to get extended memory size + * Both have the return value in AX. + * + */ + +ENTRY(get_memsize) + push %ebp + push %ebx + + mov 0xc(%esp), %ebx + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + cmpb $0x1, %bl + je xext + + int $0x12 + jmp xdone + +xext: + movb $0x88, %ah + int $0x15 + +xdone: + movw %ax, %bx + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movw %bx, %ax + pop %ebx + pop %ebp + ret + + +#ifndef NO_FANCY_STUFF + +/* + * + * get_eisamemsize() : return packed EISA memory map, lower 16 bits is + * memory between 1M and 16M in 1K parts, upper 16 bits is + * memory above 16M in 64K parts. If error, return -1. + * BIOS call "INT 15H, AH=E801H" to get EISA memory map, + * AX = memory between 1M and 16M in 1K parts. + * BX = memory above 16M in 64K parts. + * + */ + +ENTRY(get_eisamemsize) + push %ebp + push %ebx + push %ecx + push %edx + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movw $0xe801, %ax + int $0x15 + + shll $16, %ebx + movw %ax, %bx + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movl $0xFFFFFFFF, %eax + cmpb $0x86, %bh + je xnoteisa + + movl %ebx, %eax + +xnoteisa: + pop %edx + pop %ecx + pop %ebx + pop %ebp + ret + + +/* + * + * get_mem_map(addr, cont) : address and old continuation value (zero to + * start), for the Query System Address Map BIOS call. + * + * Sets the first 4-byte int value of "addr" to the size returned by + * the call. If the call fails, sets it to zero. + * + * Returns: new (non-zero) continuation value, 0 if done. + * + * NOTE: Currently hard-coded for a maximum buffer length of 1024. + */ + +ENTRY(get_mem_map) + push %ebp + push %ebx + push %ecx + push %edx + push %edi + push %esi + + /* place address (+4) in ES:DI */ + movl 0x1c(%esp), %eax + addl $4, %eax + movl %eax, %edi + andl $0xf, %edi + shrl $4, %eax + movl %eax, %esi + + /* set continuation value */ + movl 0x20(%esp), %ebx + + /* set default maximum buffer size */ + movl $0x14, %ecx + + /* set EDX to 'SMAP' */ + movl $0x534d4150, %edx + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movw %si, %es + movw $0xe820, %ax + int $0x15 + + jc xnosmap + + cmpl $0x534d4150, %eax + jne xnosmap + + cmpl $0x14, %ecx + jl xnosmap + + cmpl $0x400, %ecx + jg xnosmap + + jmp xsmap + +xnosmap: + movl $0, %ecx + +xsmap: + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + /* write length of buffer (zero if error) into "addr" */ + movl 0x1c(%esp), %eax + movl %ecx, (%eax) + + /* set return value to continuation */ + movl %ebx, %eax + + pop %esi + pop %edi + pop %edx + pop %ecx + pop %ebx + pop %ebp + ret + +/* + * gateA20(int linear) + * + * Gate address-line 20 for high memory. + * + * This routine is probably overconservative in what it does, but so what? + * + * It also eats any keystrokes in the keyboard buffer. :-( + */ + +ENTRY(gateA20) + pushl %eax + + call gloop1 + + movb $KC_CMD_WOUT, %al + outb $K_CMD + +gloopint1: + inb $K_STATUS + andb $K_IBUF_FUL, %al + jnz gloopint1 + + movb $KB_OUTPUT_MASK, %al + cmpb $0, 0x8(%esp) + jz gdoit + + orb $KB_A20_ENABLE, %al +gdoit: + outb $K_RDWR + + call gloop1 + + popl %eax + ret + +gloop1: + inb $K_STATUS + andb $K_IBUF_FUL, %al + jnz gloop1 + +gloop2: + inb $K_STATUS + andb $K_OBUF_FUL, %al + jz gloop2ret + inb $K_RDWR + jmp gloop2 + +gloop2ret: + ret + + +#ifdef DEBUG + +/* + * Don't use the next two functions anywhere but in assembly code, called + * from C, it might corrupt your register state!! + */ + +ENTRY(delay_timer) /* labels start with "dt_" */ + pushl %edx + pushl %ecx + movl 0xc(%esp), %ecx + jcxz dt_exit + movl $0x1680, %eax + mull %ecx + movl %eax, %eax +dt_label1: + subl $0x1, %eax + jne dt_label1 +dt_exit: + popl %ecx + popl %edx + ret + + +ENTRY(wait_APIC_done) /* labels start with "wa_" */ + testl $0x1000, (%edx) + je wa_label_before_exit + decl %ecx + jne EXT_C(wait_APIC_done) +wa_label_before_exit: + movl %ecx, %eax + ret + + +ENTRY(start_cpu) /* labels start with "sc_" */ + pushl %ebp + movl %esp, %ebp + pushl %ebx + pushl %edi + pushl %ecx + pushl %edx + + pushl $0xc8 + call EXT_C(delay_timer) + popl %eax + + movl 0x10(%ebp), %edx + addl $0x300, %edx + movl $0x64,%ecx + call EXT_C(wait_APIC_done) + + testl %eax, %eax + jne sc_label1 + xorl %eax, %eax + jmp sc_exit + +sc_label1: + movl 0x10(%ebp), %eax + movl 0x8(%ebp), %edi + pushl $0xa + shll $0x18, %edi + /* send assert INIT IPI */ + movl %edi, 0x310(%eax) + movl $0xc500, 0x300(%eax) + + call EXT_C(delay_timer) + popl %eax + + movl 0x10(%ebp), %ecx + pushl $0xc8 + /* send deassert INIT IPI */ + movl $0x8500, 0x300(%ecx) + + call EXT_C(delay_timer) + popl %eax + +/* 486 MP systems should exit here */ + + movl 0xc(%ebp), %ebx + movl 0x10(%ebp), %eax + andl $0xff000, %ebx + orl $0x600000, %ebx + pushl $0xc8 + shrl $0xc, %ebx + /* send STARTUP IPI */ + movl %edi, 0x310(%eax) + movl %ebx, 0x300(%eax) + + call EXT_C(delay_timer) + popl %eax + + movl 0x10(%ebp), %edx + addl $0x300, %edx + movl $0x64,%ecx + call EXT_C(wait_APIC_done) + testl %eax,%eax + movl $0x0,%eax + je sc_exit + + pushl $0x64 + call EXT_C(delay_timer) + popl %eax + + movl 0x10(%ebp), %eax + pushl $0xc8 + /* send STARTUP IPI */ + movl %edi, 0x310(%eax) + movl %ebx, 0x300(%eax) + + call EXT_C(delay_timer) + popl %eax + +sc_label_before_exit: + movl $0x1, %eax + +sc_exit: + popl %edx + popl %ecx + popl %edi + popl %ebx + popl %ebp + ret + + + .code16 + +ENTRY(patch_code) /* labels start with "pc_" */ + mov %cs, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + movl $0, 0 +pc_stop: + jmp pc_stop + movw %ax, %ax +ENTRY(patch_code_end) + + .code32 + +#endif /* DEBUG */ + + +/* + * linux_boot() + * + * Does some funky things (including on the stack!), then jumps to the + * entry point of the Linux setup code. + */ + +ENTRY(linux_boot) + /* don't worry about saving anything, we're committed at this point */ + cld /* forward copying */ + + /* XXX new stack pointer in safe area for calling functions */ + movl $0x4000, %esp + + /* copy kernel */ + movl $LINUX_SETUP, %eax + movl LINUX_KERNEL_LEN_OFFSET(%eax), %ecx + shll $2, %ecx + movl $LINUX_STAGING_AREA, %esi + movl $LINUX_KERNEL, %edi + + rep + movsl + + /* final setup for linux boot */ + + movw $LINUX_SETUP_SEG, %ax + movw %ax, segment + + xorl %eax, %eax + movl %eax, offset + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + /* final setup for linux boot */ + movw $LINUX_SETUP_STACK, %sp + + movw $LINUX_INIT_SEG, %ax + movw %ax, %ss + + /* jump to start */ + ljmp (offset) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + +/* + * multi_boot(int start, int mbi) + * + * This starts a kernel in the manner expected of the multiboot standard. + */ + +ENTRY(multi_boot) + /* no need to save anything */ + movl $0x2BADB002, %eax + movl 0x8(%esp), %ebx + + /* boot kernel here (absolute address call) */ + call *0x4(%esp) + + /* error */ + call EXT_C(stop) + + +/* + * cls() + * BIOS call "INT 10H Function 0Fh" to get current video mode + * Call with %ah = 0x0f + * Returns %al = (video mode) + * %bh = (page number) + * BIOS call "INT 10H Function 00h" to set the video mode (clears screen) + * Call with %ah = 0x00 + * %al = (video mode) + */ + + +ENTRY(cls) + push %ebp + push %eax + push %ebx /* save EBX */ + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb $0xf, %ah + int $0x10 /* Get Current Video mode */ + xorb %ah, %ah + int $0x10 /* Set Video mode (clears screen) */ + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + pop %ebx + pop %eax + pop %ebp + ret + + +/* + * getxy() + * BIOS call "INT 10H Function 03h" to get cursor position + * Call with %ah = 0x03 + * %bh = page + * Returns %ch = starting scan line + * %cl = ending scan line + * %dh = row (0 is top) + * %dl = column (0 is left) + */ + + +ENTRY(getxy) + push %ebp + push %ebx /* save EBX */ + push %ecx /* save ECX */ + push %edx + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + xorb %bh, %bh /* set page to 0 */ + movb $0x3, %ah + int $0x10 /* get cursor position */ + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movb %dl, %ah + movb %dh, %al + + pop %edx + pop %ecx + pop %ebx + pop %ebp + ret + + +/* + * gotoxy(x,y) + * BIOS call "INT 10H Function 02h" to set cursor position + * Call with %ah = 0x02 + * %bh = page + * %dh = row (0 is top) + * %dl = column (0 is left) + */ + + +ENTRY(gotoxy) + push %ebp + push %eax + push %ebx /* save EBX */ + push %edx + + movb 0x14(%esp), %dl /* %dl = x */ + movb 0x18(%esp), %dh /* %dh = y */ + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + xorb %bh, %bh /* set page to 0 */ + movb $0x2, %ah + int $0x10 /* set cursor position */ + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + pop %edx + pop %ebx + pop %eax + pop %ebp + ret + + +/* + * set_attrib(attr) : Sets the character attributes for character at + * current cursor position. + * + * Bitfields for character's display attribute: + * Bit(s) Description + * 7 foreground blink + * 6-4 background color + * 3 foreground bright + * 2-0 foreground color + * + * Values for character color: + * Normal Bright + * 000b black dark gray + * 001b blue light blue + * 010b green light green + * 011b cyan light cyan + * 100b red light red + * 101b magenta light magenta + * 110b brown yellow + * 111b light gray white + * + * BIOS call "INT 10H Function 08h" to read character and attribute data + * Call with %ah = 0x08 + * %bh = page + * Returns %ah = character attribute + * %al = character value + * BIOS call "INT 10H Function 09h" to write character and attribute data + * Call with %ah = 0x09 + * %al = character value + * %bh = page + * %bl = character attribute + * %cx = count to display (???, possible side-effects!!) + */ + +ENTRY(set_attrib) + push %ebp + push %eax + push %ebx + push %ecx + + movl 0x14(%esp), %ecx + xorl %ebx, %ebx + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb $0x8, %ah + int $0x10 + movb $0x9, %ah + movb %cl, %bl + movw $1, %cx + int $0x10 + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + pop %ecx + pop %ebx + pop %eax + pop %ebp + ret + + +/* + * getrtsecs() + * if a seconds value can be read, read it and return it (BCD), + * otherwise return 0xFF + * BIOS call "INT 1AH Function 02H" to check whether a character is pending + * Call with %ah = 0x2 + * Return: + * If RT Clock can give correct values + * %ch = hour (BCD) + * %cl = minutes (BCD) + * %dh = seconds (BCD) + * %dl = daylight savings time (00h std, 01h daylight) + * Carry flag = clear + * else + * Carry flag = set + * (this indicates that the clock is updating, or + * that it isn't running) + */ +ENTRY(getrtsecs) + push %ebp + push %ecx + push %edx + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb $0x2, %ah + int $0x1a + + jnc gottime + movb $0xff, %dh + +gottime: + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movb %dh, %al + + pop %edx + pop %ecx + pop %ebp + ret + + +/* + * asm_getkey() + * BIOS call "INT 16H Function 00H" to read character from keyboard + * Call with %ah = 0x0 + * Return: %ah = keyboard scan code + * %al = ASCII character + */ + +ENTRY(asm_getkey) + push %ebp + push %ebx /* save %ebx */ + + call EXT_C(prot_to_real) + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + int $0x16 + + movw %ax, %bx /* real_to_prot uses %eax */ + + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + movw %bx, %ax + + pop %ebx + pop %ebp + ret + + +/* + * checkkey() + * if there is a character pending, return it; otherwise return -1 + * BIOS call "INT 16H Function 01H" to check whether a character is pending + * Call with %ah = 0x1 + * Return: + * If key waiting to be input: + * %ah = keyboard scan code + * %al = ASCII character + * Zero flag = clear + * else + * Zero flag = set + */ +ENTRY(checkkey) + push %ebp + push %ebx + + xorl %ebx, %ebx + + call EXT_C(prot_to_real) /* enter real mode */ + + /* + * The ".code16" directive only works in GAS, the GNU assembler! + * This adds 32-bit data or addressing directives so that this + * code will work in real mode! + */ + .code16 + + movb $0x1, %ah + int $0x16 + + jz notpending + movw %ax, %bx + jmp pending + +notpending: + movl $0xFFFFFFFF, %ebx + +pending: + call EXT_C(real_to_prot) + + /* + * The ".code32" directive only works in GAS, the GNU assembler! + * This gets out of "16-bit" mode. + */ + .code32 + + mov %ebx, %eax + + pop %ebx + pop %ebp + ret + +#endif /* NO_FANCY_STUFF */ + +/* + * This is the area for all of the special variables. + */ + +protstack: + .long PROTSTACKINIT + +VARIABLE(boot_drive) + .long 0 + + /* an address can only be long-jumped to if it is in memory, this + is used by multiple routines */ +offset: + .long 0x8000 +segment: + .word 0 + +/* + * This is the Global Descriptor Table + * + * An entry, a "Segment Descriptor", looks like this: + * + * 31 24 19 16 7 0 + * ------------------------------------------------------------ + * | | |B| |A| | | |1|0|E|W|A| | + * | BASE 31..24 |G|/|0|V| LIMIT |P|DPL| TYPE | BASE 23:16 | + * | | |D| |L| 19..16| | |1|1|C|R|A| | + * ------------------------------------------------------------ + * | | | + * | BASE 15..0 | LIMIT 15..0 | + * | | | + * ------------------------------------------------------------ + * + * Note the ordering of the data items is reversed from the above + * description. + */ + +gdt: + .word 0, 0 + .byte 0, 0, 0, 0 + + /* code segment */ + .word 0xFFFF, 0 + .byte 0, 0x9E, 0xCF, 0 + + /* data segment */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0xCF, 0 + + /* 16 bit real mode CS */ + .word 0xFFFF, 0 + .byte 0, 0x9E, 0, 0 + + /* 16 bit real mode DS */ + .word 0xFFFF, 0 + .byte 0, 0x92, 0, 0 + + +/* this is the GDT descriptor */ +gdtdesc: + .word 0x27 /* limit */ + .long gdt /* addr */ + + diff --git a/shared_src/boot.c b/shared_src/boot.c new file mode 100644 index 000000000..1f5a6d0ff --- /dev/null +++ b/shared_src/boot.c @@ -0,0 +1,540 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#define _BOOT_C + +#include "shared.h" + +#include "freebsd.h" +#include "imgact_aout.h" +#include "i386-elf.h" + +char *cur_cmdline; +static int cur_addr; +entry_func entry_addr; +static struct mod_list mll[99]; + + +/* + * The next two functions, 'load_image' and 'load_module', are the building + * blocks of the multiboot loader component. They handle essentially all + * of the gory details of loading in a bootable image and the modules. + */ + +int +load_image(void) +{ + int len, i, exec_type, align_4k = 1, type = 0; + unsigned long flags = 0, text_len, data_len, bss_len; + char *str, *str2; + union { + struct multiboot_header *mb; + struct exec *aout; + Elf32_Ehdr *elf; + } pu; + /* presuming that MULTIBOOT_SEARCH is large enough to encompass an + executable header */ + unsigned char buffer[MULTIBOOT_SEARCH]; + + /* sets the header pointer to point to the beginning of the + buffer by default */ + pu.aout = (struct exec *) buffer; + + if (!open(cur_cmdline)) + return 0; + + if (!(len = read((int)buffer, MULTIBOOT_SEARCH)) || len < 32) + { + if (!errnum) + errnum = ERR_EXEC_FORMAT; + + return 0; + } + + for (i = 0; i < len; i++) + { + if (MULTIBOOT_FOUND((int)(buffer+i), len-i)) + { + flags = ((struct multiboot_header *) (buffer+i))->flags; + if (flags & MULTIBOOT_UNSUPPORTED) + { + errnum = ERR_BOOT_FEATURES; + return 0; + } + type = 'm'; + str2 = "Multiboot"; + break; + } + } + + /* ELF loading only supported if kernel using multiboot */ + if (type == 'm' && len > sizeof(Elf32_Ehdr) + && BOOTABLE_I386_ELF((*((Elf32_Ehdr *)buffer)))) + { + entry_addr = (entry_func) pu.elf->e_entry; + + if (((int)entry_addr) < 0x100000) + errnum = ERR_BELOW_1MB; + + /* don't want to deal with ELF program header at some random + place in the file -- this generally won't happen */ + if (pu.elf->e_phoff == 0 || pu.elf->e_phnum == 0 + || ((pu.elf->e_phoff + (pu.elf->e_phentsize * pu.elf->e_phnum)) + >= len)) + errnum = ERR_EXEC_FORMAT; + + exec_type = 0; + str = "elf"; + } + else if (flags & MULTIBOOT_AOUT_KLUDGE) + { + pu.mb = (struct multiboot_header *) (buffer+i); + entry_addr = (entry_func) pu.mb->entry_addr; + cur_addr = pu.mb->load_addr; + /* first offset into file */ + filepos = i - (pu.mb->header_addr - cur_addr); + text_len = pu.mb->load_end_addr - cur_addr; + data_len = 0; + bss_len = pu.mb->bss_end_addr - pu.mb->load_end_addr; + + if (pu.mb->header_addr < pu.mb->load_addr + || pu.mb->load_end_addr <= pu.mb->load_addr + || pu.mb->bss_end_addr < pu.mb->load_end_addr + || (pu.mb->header_addr - pu.mb->load_addr) > i) + errnum = ERR_EXEC_FORMAT; + + if (cur_addr < 0x100000) + errnum = ERR_BELOW_1MB; + + pu.aout = (struct exec *) buffer; + exec_type = 2; + str = "kludge"; + } + else if (len > sizeof(struct exec) && !N_BADMAG((*(pu.aout)))) + { + entry_addr = (entry_func) pu.aout->a_entry; + + if (!type) + { + /* + * If it doesn't have a Multiboot header, then presume + * it is either a FreeBSD or NetBSD executable. If so, + * then use a magic number of normal ordering, ZMAGIC to + * determine if it is FreeBSD. + * + * This is all because freebsd and netbsd seem to require + * masking out some address bits... differently for each + * one... plus of course we need to know which booting + * method to use. + */ + if (buffer[0] == 0xb && buffer[1] == 1) + { + type = 'f'; + entry_addr = (entry_func) (((int)entry_addr) & 0xFFFFFF); + str2 = "FreeBSD"; + } + else + { + type = 'n'; + entry_addr = (entry_func) (((int)entry_addr) & 0xF00000); + if (N_GETMAGIC((*(pu.aout))) != NMAGIC) + align_4k = 0; + str2 = "NetBSD"; + } + } + + cur_addr = (int) entry_addr; + /* first offset into file */ + filepos = N_TXTOFF((*(pu.aout))); + text_len = pu.aout->a_text; + data_len = pu.aout->a_data; + bss_len = pu.aout->a_bss; + + if (cur_addr < 0x100000) + errnum = ERR_BELOW_1MB; + + exec_type = 1; + str = "a.out"; + } + else if ((*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET)) + == BOOTSEC_SIGNATURE) + && ((data_len + = (((long)*((unsigned char *) + (buffer+LINUX_SETUP_LEN_OFFSET))) << 9)) + <= LINUX_SETUP_MAXLEN) + && ((text_len + = (((long)*((unsigned short *) + (buffer+LINUX_KERNEL_LEN_OFFSET))) << 4)) + <= LINUX_KERNEL_MAXLEN) + && (data_len+text_len+SECTOR_SIZE) <= ((filemax+15)&0xFFFFFFF0)) + { + printf(" Loading: [format=Linux-piggyback, setup=0x%x, size=0x%x]\n", + data_len, text_len); + + if (mbi.mem_lower >= 608) + { + bcopy(buffer, (char *)LINUX_SETUP, data_len+SECTOR_SIZE); + + /* copy command-line plus memory hack to staging area */ + { + char *src = cur_cmdline; + char *dest = (char *) (CL_MY_LOCATION+4); + + bcopy("mem=", (char *)CL_MY_LOCATION, 4); + + *((unsigned short *) CL_OFFSET) = CL_MY_LOCATION-CL_BASE_ADDR; + *((unsigned short *) CL_MAGIC_ADDR) = CL_MAGIC; + + dest = convert_to_ascii(dest, 'u', (mbi.mem_upper+0x400)); + *(dest++) = 'K'; + *(dest++) = ' '; + + while (*src && *src != ' ') + src++; + + while (((int)dest) < CL_MY_END_ADDR && (*(dest++) = *(src++))); + + *dest = 0; + } + + /* offset into file */ + filepos = data_len+SECTOR_SIZE; + + if (read(LINUX_STAGING_AREA, text_len) >= (text_len-16)) + return 'l'; + else if (!errnum) + errnum = ERR_EXEC_FORMAT; + } + else + errnum = ERR_WONT_FIT; + } + else /* no recognizable format */ + errnum = ERR_EXEC_FORMAT; + + /* return if error */ + if (errnum) + return 0; + + /* fill the multiboot info structure */ + mbi.cmdline = (int)cur_cmdline; + mbi.mods_count = 0; + mbi.mods_addr = 0; + mbi.boot_device = (saved_drive << 24) | saved_partition; + mbi.flags &= ~(MB_INFO_MODS | MB_INFO_AOUT_SYMS | MB_INFO_ELF_SHDR); + mbi.syms.a.tabsize = 0; + mbi.syms.a.strsize = 0; + mbi.syms.a.addr = 0; + mbi.syms.a.pad = 0; + + printf(" Loading: [format=%s-%s", str2, str); + + str = ""; + + if (exec_type) /* can be loaded like a.out */ + { + if (flags & MULTIBOOT_AOUT_KLUDGE) + str = "-and-data"; + + printf(", loadaddr=0x%x, text%s=0x%x", cur_addr, str, text_len); + + /* read text, then read data */ + if (read(cur_addr, text_len) == text_len) + { + cur_addr += text_len; + + if (!(flags & MULTIBOOT_AOUT_KLUDGE)) + { + /* we have to align to a 4K boundary */ + if (align_4k) + cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; + else + printf(", C"); + + printf(", data=0x%x", data_len); + + if (read(cur_addr, data_len) != data_len && !errnum) + errnum = ERR_EXEC_FORMAT; + cur_addr += data_len; + } + + if (!errnum) + { + bzero((char*)cur_addr, bss_len); + cur_addr += bss_len; + + printf(", bss=0x%x", str, bss_len); + } + } + else if (!errnum) + errnum = ERR_EXEC_FORMAT; + + if (!errnum && pu.aout->a_syms + && pu.aout->a_syms < (filemax - filepos)) + { + int symtab_err, orig_addr = cur_addr; + + /* we should align to a 4K boundary here for good measure */ + cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; + + mbi.syms.a.addr = cur_addr; + + *(((int *)cur_addr)++) = pu.aout->a_syms; + + printf(", symtab=0x%x", pu.aout->a_syms); + + if (read(cur_addr, pu.aout->a_syms) == pu.aout->a_syms) + { + cur_addr += pu.aout->a_syms; + mbi.syms.a.tabsize = pu.aout->a_syms; + + if (read((int)(&i), sizeof(int)) == sizeof(int)) + { + *(((int *)cur_addr)++) = i; + + mbi.syms.a.strsize = i; + + i -= sizeof(int); + + printf(", strtab=0x%x", i); + + symtab_err = (read(cur_addr, i) != i); + cur_addr += i; + } + else + symtab_err = 1; + } + else + symtab_err = 1; + + if (symtab_err) + { + printf("(bad)"); + cur_addr = orig_addr; + mbi.syms.a.tabsize = 0; + mbi.syms.a.strsize = 0; + mbi.syms.a.addr = 0; + } + else + mbi.flags |= MB_INFO_AOUT_SYMS; + } + } + else /* ELF executable */ + { + int loaded = 0, memaddr, memsiz, filesiz; + Elf32_Phdr *phdr; + + /* reset this to zero for now */ + cur_addr = 0; + + /* scan for program segments */ + for (i = 0; i < pu.elf->e_phnum; i++) + { + phdr = (Elf32_Phdr *) + (pu.elf->e_phoff + ((int)buffer) + + (pu.elf->e_phentsize * i)); + if (phdr->p_type == PT_LOAD) + { + /* offset into file */ + filepos = phdr->p_offset; + filesiz = phdr->p_filesz; + memaddr = phdr->p_vaddr; + memsiz = phdr->p_memsz; + if (memaddr < 0x100000) + errnum = ERR_BELOW_1MB; + /* make sure we only load what we're supposed to! */ + if (filesiz > memsiz) + filesiz = memsiz; + /* mark memory as used */ + if (cur_addr < memaddr+memsiz) + cur_addr = memaddr+memsiz; + printf(", <0x%x:0x%x:0x%x>", str, memaddr, filesiz, + memsiz-filesiz); + /* increment number of segments */ + loaded++; + + /* load the segment */ + if (memcheck(memaddr, memsiz) + && read(memaddr, filesiz) == filesiz) + { + if (memsiz > filesiz) + bzero((char *)(memaddr+filesiz), memsiz-filesiz); + } + else + break; + } + } + + if (!errnum) + { + if (!loaded) + errnum = ERR_EXEC_FORMAT; + else + { + /* XXX load symbols */ + } + } + } + + if (!errnum) + printf(", entry=0x%x]\n", str, (int)entry_addr); + else + { + putchar('\n'); + type = 0; + } + + return type; +} + +int +load_module(void) +{ + int len; + + /* if we are supposed to load on 4K boundaries */ + cur_addr = (cur_addr + 0xFFF) & 0xFFFFF000; + + if (!open(cur_cmdline) || !(len = read(cur_addr, -1))) + return 0; + + /* these two simply need to be set if any modules are loaded at all */ + mbi.flags |= MB_INFO_MODS; + mbi.mods_addr = (int)mll; + + mll[mbi.mods_count].cmdline = (int)cur_cmdline; + mll[mbi.mods_count].mod_start = cur_addr; + cur_addr += len; + mll[mbi.mods_count].mod_end = cur_addr; + mll[mbi.mods_count].pad = 0; + + /* increment number of modules included */ + mbi.mods_count++; + + return 1; +} + + +/* + * All "*_boot" commands depend on the images being loaded into memory + * correctly, the variables in this file being set up correctly, and + * the root partition being set in the 'saved_drive' and 'saved_partition' + * variables. + */ + + +void +bsd_boot(int type, int bootdev) +{ + char *str; + int clval = 0, i; + struct bootinfo bi; + + while (*(++cur_cmdline) && *cur_cmdline != ' '); + str = cur_cmdline; + while (*str) + { + if (*str == '-') + { + while(*str && *str != ' ') + { + if (*str == 'C') + clval |= RB_CDROM; + if (*str == 'a') + clval |= RB_ASKNAME; + if (*str == 'b') + clval |= RB_HALT; + if (*str == 'c') + clval |= RB_CONFIG; + if (*str == 'd') + clval |= RB_KDB; + if (*str == 'h') + clval |= RB_SERIAL; + if (*str == 'r') + clval |= RB_DFLTROOT; + if (*str == 's') + clval |= RB_SINGLE; + if (*str == 'v') + clval |= RB_VERBOSE; + str++; + } + continue; + } + str++; + } + + if (type == 'f') + { + clval |= RB_BOOTINFO; + + bi.bi_version = BOOTINFO_VERSION; + + *cur_cmdline = 0; + while ((--cur_cmdline) > (char *)(mbi.cmdline) && *cur_cmdline != '/'); + if (*cur_cmdline == '/') + bi.bi_kernelname = cur_cmdline+1; + else + bi.bi_kernelname = 0; + + bi.bi_nfs_diskless = 0; + bi.bi_n_bios_used = 0; /* this field is apparently unused */ + + for(i = 0; i < N_BIOS_GEOM; i++) + bi.bi_bios_geom[i] = get_diskinfo(i + 0x80); + + bi.bi_size = sizeof(struct bootinfo); + bi.bi_memsizes_valid = 1; + bi.bi_basemem = mbi.mem_lower; + bi.bi_extmem = mbi.mem_upper; + bi.bi_symtab = mbi.syms.a.addr; + bi.bi_esymtab = mbi.syms.a.addr + 4 + + mbi.syms.a.tabsize + mbi.syms.a.strsize; + + /* call entry point */ + (*entry_addr)(clval, bootdev, 0, 0, 0, ((int)(&bi))); + } + else + { + /* + * We now pass the various bootstrap parameters to the loaded + * image via the argument list. + * + * This is the official list: + * + * arg0 = 8 (magic) + * arg1 = boot flags + * arg2 = boot device + * arg3 = start of symbol table (0 if not loaded) + * arg4 = end of symbol table (0 if not loaded) + * arg5 = transfer address from image + * arg6 = transfer address for next image pointer + * arg7 = conventional memory size (640) + * arg8 = extended memory size (8196) + * + * ...in actuality, we just pass the parameters used by the kernel. + */ + + /* call entry point */ + (*entry_addr)(clval, bootdev, 0, + (mbi.syms.a.addr + 4 + + mbi.syms.a.tabsize + mbi.syms.a.strsize), + mbi.mem_upper, mbi.mem_lower); + } +} + diff --git a/shared_src/char_io.c b/shared_src/char_io.c new file mode 100644 index 000000000..bbb22248b --- /dev/null +++ b/shared_src/char_io.c @@ -0,0 +1,611 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#define _CHAR_IO_C + +#include "shared.h" + +#ifndef NO_FANCY_STUFF +int +getkey(void) +{ + buf_drive = -1; + return asm_getkey(); +} +#endif /* NO_FANCY_STUFF */ + + +void +print_error(void) +{ + if (errnum > ERR_NONE && errnum < MAX_ERR_NUM) +#ifndef NO_FANCY_STUFF + /* printf("\7\n %s\n", err_list[errnum]); */ + printf("\n %s\n", err_list[errnum]); +#else /* NO_FANCY_STUFF */ + printf("Error: %d\n", errnum); +#endif /* NO_FANCY_STUFF */ + + errnum = ERR_NONE; +} + + +char * +convert_to_ascii(char *buf, int c, ...) +{ + unsigned long num = *((&c) + 1), mult = 10; + char *ptr = buf; + + if (c == 'x') + mult = 16; + + if ((num & 0x80000000uL) && c == 'd') + { + num = (~num)+1; + *(ptr++) = '-'; + buf++; + } + + do + { + int dig = num % mult; + *(ptr++) = ( (dig > 9) ? dig + 'a' - 10 : '0' + dig ); + } + while (num /= mult); + + /* reorder to correct direction!! */ + { + char *ptr1 = ptr-1; + char *ptr2 = buf; + while (ptr1 > ptr2) + { + int c = *ptr1; + *ptr1 = *ptr2; + *ptr2 = c; + ptr1--; + ptr2++; + } + } + + return ptr; +} + + +void +printf(char *format, ... ) +{ + int *dataptr = (int *) &format; + char c, *ptr, str[16]; + + dataptr++; + + while (c = *(format++)) + { + if (c != '%') + putchar(c); + else + switch (c = *(format++)) + { + case 'd': case 'u': case 'x': + *convert_to_ascii(str, c, *((unsigned long *) dataptr++)) = 0; + + ptr = str; + + while (*ptr) + putchar(*(ptr++)); + break; + + case 'c': putchar((*(dataptr++))&0xff); break; + + case 's': + ptr = (char *)(*(dataptr++)); + + while (c = *(ptr++)) + putchar(c); + break; + } + } +} + + +#ifndef NO_FANCY_STUFF + +void +init_page(void) +{ + cls(); + + printf("\n GRUB version %s (%dK lower / %dK upper memory)\n\n", + version_string, mbi.mem_lower, mbi.mem_upper); +} + + +/* don't use this with a maxlen greater than 1600 or so! the problem + is that it depends on the whole thing fitting on the screen at once, + and the whole screen is about 2000 characters, minus the prompt... + so want to leave space for an error line, etc. + maxlen should be at least 1, and we shouldn't have a NULL prompt or + cmdline... the cmdline must be a valid string at the start */ + +int +get_cmdline(char *prompt, char *commands, char *cmdline, int maxlen) +{ + int ystart, yend, xend, lpos, c; + int plen = 0; + int llen = 0; + + /* nested function definition for code simplicity XXX GCC only, I think */ + void cl_print(char *str) + { + while (*str != 0) + { + putchar(*(str++)); + if (++xend > 78) + { + xend = 0; + putchar(' '); + if (yend == (getxy() & 0xFF)) + ystart--; + else + yend++; + } + } + } + /* nested function definition for code simplicity XXX GCC only, I think */ + void cl_setcpos(void) + { + yend = ((lpos+plen) / 79) + ystart; + xend = ((lpos+plen) % 79); + gotoxy(xend, yend); + } + + /* nested function definition for initial command-line printing */ + void cl_init() + { + /* distinguish us from other lines and error messages! */ + putchar('\n'); + + /* print full line and set position here */ + ystart = (getxy() & 0xFF); + yend = ystart; + xend = 0; + cl_print(prompt); + cl_print(cmdline); + cl_setcpos(); + } + + /* nested function definition for erasing to the end of the line */ + void cl_kill_to_end() + { + int i; + cmdline[lpos] = 0; + for (i = lpos; i <= llen; i++) + { + if (i && ((i + plen) % 79) == 0) + putchar(' '); + putchar(' '); + } + llen = lpos; + cl_setcpos(); + } + + while (prompt[plen]) + plen++; + while (cmdline[llen]) + llen++; + /* XXX limiting maxlen to 1600 */ + if (maxlen > 1600) + { + maxlen = 1600; + if (llen > 1599) + { + llen = 1599; + cmdline[1600] = 0; + } + } + lpos = llen; + + cl_init(); + + while (ASCII_CHAR(c = getkey()) != '\n' && ASCII_CHAR(c) != '\r') + { + switch (c) + { + case KEY_LEFT: + c = 2; + break; + case KEY_RIGHT: + c = 6; + break; + case KEY_HOME: + c = 1; + break; + case KEY_END: + c = 5; + break; + case KEY_DELETE: + c = 8; + default: + } + + c = ASCII_CHAR(c); + + switch (c) + { + case 27: /* ESC immediately return 1*/ + return 1; + case 9: /* TAB lists completions */ + { + int i, j = 0, llen_old = llen; + + while (cmdline[j] && cmdline[j] != '=') + j++; + + /* since the command line cannot have a '\n', we're OK to use c */ + c = cmdline[lpos]; + + cl_kill_to_end(); + + /* goto part after line here */ + yend = ((llen+plen) / 79) + ystart; + gotoxy(0, yend); putchar('\n'); + + if (lpos > j) + { + for (i = lpos; i > 0 && cmdline[i-1] != ' '; i--); + if (i <= j) + i = j+1; + /* print possible completions */ + print_completions(cmdline+i); + } + else if (commands) + printf(commands); + else + break; + + /* restore command-line */ + cmdline[lpos] = c; + llen = llen_old; + cl_init(); + } + break; + case 1: /* C-a go to beginning of line */ + lpos = 0; + cl_setcpos(); + break; + case 5: /* C-e go to end of line */ + lpos = llen; + cl_setcpos(); + break; + case 6: /* C-f forward one character */ + if (lpos < llen) + { + lpos++; + cl_setcpos(); + } + break; + case 2: /* C-b backward one character */ + if (lpos > 0) + { + lpos--; + cl_setcpos(); + } + break; + case 4: /* C-d delete character under cursor */ + if (lpos == llen) + break; + lpos++; + /* fallthrough is on purpose! */ + case 8: /* C-h backspace */ + if (lpos > 0) + { + int i; + for (i = lpos-1; i < llen; i++) + cmdline[i] = cmdline[i+1]; + i = lpos; + lpos = llen - 1; + cl_setcpos(); + putchar(' '); + lpos = i - 1; /* restore lpos and decrement */ + llen--; + cl_setcpos(); + if (lpos != llen) + { + cl_print(cmdline+lpos); + cl_setcpos(); + } + } + break; + case 21: /* C-u kill to beginning of line */ + if (lpos == 0) + break; + { + int i; + for (i = 0; i < (llen-lpos); i++) + cmdline[i] = cmdline[lpos+i]; + } + lpos = llen-lpos; + cl_setcpos(); + /* fallthrough on purpose! */ + case 11: /* C-k kill to end of line */ + if (lpos < llen) + { + cl_kill_to_end(); + if (c == 21) + { + lpos = 0; + cl_setcpos(); + cl_print(cmdline); + cl_setcpos(); + } + } + break; + default: /* insert printable character into line */ + if (llen < (maxlen-1) && c >= ' ' && c <= '~') + { + if (lpos == llen) + { + cmdline[lpos] = c; + cmdline[lpos+1] = 0; + cl_print(cmdline+lpos); + lpos++; + } + else + { + int i; + for (i = llen; i >= lpos; i--) + cmdline[i+1] = cmdline[i]; + cmdline[lpos] = c; + cl_setcpos(); + cl_print(cmdline+lpos); + lpos++; + cl_setcpos(); + } + llen++; + } + } + } + + /* goto part after line here */ + yend = ((llen+plen) / 79) + ystart; + gotoxy(0, yend); putchar('\n'); + + /* remove leading spaces */ + /* use c and lpos as indexes now */ + for (lpos = 0; cmdline[lpos] == ' '; lpos++); + + if (lpos != 0) + { + c = 0; + do + { + cmdline[c] = cmdline[lpos]; + c++; + lpos++; + } + while (cmdline[lpos]); + } + + cmdline[c] = 0; + + return 0; +} + +#endif /* NO_FANCY_STUFF */ + + +int +get_based_digit(int c, int base) +{ + int digit = -1; + + /* make sure letter in the the range we can check! */ + c = tolower(c); + + /* + * Is it in the range between zero and nine? + */ + if (base > 0 && c >= '0' && c <= '9' && c < (base + '0')) + { + digit = c - '0'; + } + + /* + * Is it in the range used by a letter? + */ + if (base > 10 && c >= 'a' && c <= 'z' && c < ((base - 10) + 'a')) + { + digit = c - 'a' + 10; + } + + return digit; +} + + +int +safe_parse_maxint(char **str_ptr, int *myint_ptr) +{ + register char *ptr = *str_ptr; + register int myint = 0, digit; + int mult = 10, found = 0; + + /* + * Is this a hex number? + */ + if (*ptr == '0' && tolower(*(ptr+1)) == 'x') + { + ptr += 2; + mult = 16; + } + + while ((digit = get_based_digit(*ptr, mult)) != -1) + { + found = 1; + if (myint > ((MAXINT - digit)/mult)) + { + errnum = ERR_NUMBER_PARSING; + return 0; + } + myint = (myint * mult) + digit; + ptr++; + } + + if (!found) + { + errnum = ERR_NUMBER_PARSING; + return 0; + } + + *str_ptr = ptr; + *myint_ptr = myint; + + return 1; +} + + +int +tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + return (c + ('a' - 'A')); + + return c; +} + + +int +isspace(int c) +{ + if (c == ' ' || c == '\t' || c == '\n') + return 1; + + return 0; +} + + +int +strncat(char *s1, char *s2, int n) +{ + int i = -1; + + while (++i < n && s1[i] != 0); + + while (i < n && (s1[i++] = *(s2++)) != 0); + + s1[n-1] = 0; + + if (i >= n) + return 0; + + s1[i] = 0; + + return 1; +} + + +int +strcmp(char *s1, char *s2) +{ + while (*s1 == *s2) + { + if (!*(s1++)) + return 0; + s2++; + } + + if (*s1 == 0) + return -1; + + return 1; +} + + +char * +strstr(char *s1, char *s2) +{ + char *ptr, *tmp; + + while (*s1) + { + ptr = s1; + tmp = s2; + + while (*s1 && *s1++ == *tmp++); + + if (tmp > s2 && !*(tmp-1)) + return ptr; + } + + return 0; +} + + +int +memcheck(int start, int len) +{ + if ( (start < 0x1000) || (start < 0x100000 + && (mbi.mem_lower * 1024) < (start+len)) + || (start >= 0x100000 + && (mbi.mem_upper * 1024) < ((start-0x100000)+len)) ) + errnum = ERR_WONT_FIT; + + return (!errnum); +} + + +int +bcopy(char *from, char *to, int len) +{ + if (memcheck((int)to, len)) + { + if ((to >= from+len) || (to <= from)) + { + while (len > 3) + { + len -= 4; + *(((unsigned long *)to)++) = *(((unsigned long *)from)++); + } + while (len-- > 0) + *(to++) = *(from++); + } + else + { + while (len-- > 0) + to[len] = from[len]; + } + } + + return (!errnum); +} + + +int +bzero(char *start, int len) +{ + if (memcheck((int)start, len)) + { + while (len-- > 0) + *(start++) = 0; + } + + return (!errnum); +} + + diff --git a/shared_src/cmdline.c b/shared_src/cmdline.c new file mode 100644 index 000000000..f3b89a402 --- /dev/null +++ b/shared_src/cmdline.c @@ -0,0 +1,890 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define _CMDLINE_C + +#include "shared.h" + +#ifdef DEBUG + +unsigned long apic_addr; + +int start_cpu(int cpu_num, int start_addr, unsigned long my_apic_addr); + +extern char patch_code[]; +extern char patch_code_end[]; + +unsigned long reg_table[] = + { 0x20, 0x30, 0x80, 0x90, 0xa0, 0xd0, 0xe0, 0xf0, 0x280, 0x300, 0x310, + 0x320, 0x350, 0x360, 0x370, 0x380, 0x390, 0x3e0, 0 }; + + +int +get_remote_APIC_reg(int cpu_num, int reg, unsigned long *retval) +{ + int i, j = 1000; + + i = *((volatile unsigned long *) (apic_addr+0xc0)); + *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); + i = *((volatile unsigned long *) (apic_addr+0xc0)); + *((volatile unsigned long *) (apic_addr+0x300)) = (0x300 | (reg>>4)); + + while (((i = (*((volatile unsigned long *) (apic_addr+0x300)) & 0x30000)) + == 1) && (--j)); + + if (!i || i == 3 || j == 0) + return 1; + + *retval = *((volatile unsigned long *) (apic_addr+0xc0)); + + return 0; +} + + +void +list_regs(int cpu_num) +{ + int i = 0, j = 0; + unsigned long tmpval; + + while (reg_table[i] != 0) + { + printf(" %x: ", reg_table[i]); + + if (cpu_num == -1) + tmpval = *((volatile unsigned long *) (apic_addr+reg_table[i])); + else if (get_remote_APIC_reg(cpu_num, reg_table[i], &tmpval)) + printf("error!"); + + printf("%x", tmpval); + + i++; + j++; + + if (j == 5 || reg_table[i] == 0) + { + j = 0; + putchar('\n'); + } + else + putchar(','); + } +} + + +void +boot_cpu(int cpu_num) +{ + int i, start_addr = (128 * 1024); + + bcopy( patch_code, ((char *) start_addr), + ((int) patch_code_end) - ((int) patch_code) ); + + outb(0x70, 0xf); + *((volatile unsigned short *) 0x467) = 0; + *((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4)); + outb(0x71, 0xa); + + print_error(); + + printf("Starting probe for CPU #%d... value = (%x)\n", + cpu_num, *((int *) start_addr) ); + + i = start_cpu(cpu_num, start_addr, apic_addr); + + printf("Return value = (%x), waiting for RET...", i); + + i = getc(); + + outb(0x70, 0xf); + printf("\nEnding value = (%x), Status code = (%x)\n", + *((int *) start_addr), (unsigned long)inb(0x71)); +} + + +unsigned char +sum(unsigned char *addr, int len) +{ + int i; + unsigned long retval = 0; + + for (i = 0; i < len; i++) + { + retval += addr[len]; + } + + return ((unsigned char)(retval & 0xFF)); +} + + +int +get_mp_parameters(unsigned char *addr) +{ + int i, may_be_bad; + unsigned long backup; + + if (((int)addr)&0xF || addr[0] != '_' || addr[1] != 'M' || addr[2] != 'P' + || addr[3] != '_') + return 0; + + may_be_bad = 0; + + if (sum(addr, addr[8] * 16)) + { + printf("Found MP structure but checksum bad, use (y/n) ?"); + i = getc(); + putchar('\n'); + if (i != 'y') + return 0; + may_be_bad = 1; + } + + backup = apic_addr; + + printf("MP Floating Pointer Structure (address, then 12 bytes starting at 4): + %x, %x, %x, %x\n", (int)addr, + *((int *)(addr+4)), *((int *)(addr+8)), *((int *)(addr+12))); + + if (*((int *)(addr+4)) != 0) + { + addr = *((unsigned char **)(addr+4)); + apic_addr = *((unsigned long *)(addr+0x24)); + printf("MP Configuration Table, local APIC at (%x)\n", apic_addr); + } + + if (may_be_bad) + { + printf("Use this entry (y/n) ?"); + i = getc(); + putchar('\n'); + if (i != 'y') + { + apic_addr = backup; + return 0; + } + } + + return 1; +} + + +int +probe_mp_table(void) +{ + int i, probe_addr = *((unsigned short *)0x40E); + + probe_addr <<= 4; + + if (probe_addr > 0 && probe_addr <= 639*1024 + && *((unsigned char *) probe_addr) > 0 + && probe_addr + *((unsigned char *) probe_addr) * 0x400 <= 640*1024) + { + for (i = 0; i < 1024; i += 16) + { + if (get_mp_parameters((unsigned char *)(probe_addr+i))) + return 1; + } + } + + /* + * Technically, if there is an EBDA, we shouldn't search the last + * KB of memory, but I don't think it will be a problem. + */ + + if (mbi.mem_lower > 512) + probe_addr = 639 * 1024; + else + probe_addr = 511 * 1024; + + for (i = 0; i < 1024; i += 16) + { + if (get_mp_parameters((unsigned char *)(probe_addr+i))) + return 1; + } + + for (probe_addr = 0xF0000; probe_addr < 0x100000; probe_addr += 16) + { + if (get_mp_parameters((unsigned char *)probe_addr)) + return 1; + } + + return 0; +} + + +void +copy_patch_code(void) +{ + int start_addr = (128 * 1024); + + bcopy( patch_code, ((char *) start_addr), + ((int) patch_code_end) - ((int) patch_code) ); + + outb(0x70, 0xf); + *((volatile unsigned short *) 0x467) = 0; + *((volatile unsigned short *) 0x469) = ((unsigned short)(start_addr >> 4)); + outb(0x71, 0xa); + + print_error(); +} + + +void +send_init(int cpu_num) +{ + int i, start_addr = (128 * 1024); + + *((volatile unsigned long *) (apic_addr+0x280)) = 0; + i = *((volatile unsigned long *) (apic_addr+0x280)); + + *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); + i = *((volatile unsigned long *) (apic_addr+0x280)); + *((volatile unsigned long *) (apic_addr+0x300)) = 0xc500; + + for (i = 0; i < 100000; i++); + + *((volatile unsigned long *) (apic_addr+0x300)) = 0x8500; + + for (i = 0; i < 1000000; i++); + + i = *((volatile unsigned long *) (apic_addr+0x280)); + + i &= 0xEF; + + if (i) + printf("APIC error (%x)\n", i); +} + + +void +send_startup(int cpu_num) +{ + int i, start_addr = (128 * 1024); + + printf("Starting value = (%x)\n", *((int *) start_addr) ); + + *((volatile unsigned long *) (apic_addr+0x280)) = 0; + i = *((volatile unsigned long *) (apic_addr+0x280)); + + *((volatile unsigned long *) (apic_addr+0x310)) = (cpu_num << 24); + i = *((volatile unsigned long *) (apic_addr+0x280)); + *((volatile unsigned long *) (apic_addr+0x300)) = (0x600 | (start_addr>>12)); + + for (i = 0; i < 100000; i++); + + i = *((volatile unsigned long *) (apic_addr+0x280)); + + i &= 0xEF; + + if (i) + printf("APIC error (%x)\n", i); + else + { + printf("Waiting for RET..."); + + i = getc(); + + outb(0x70, 0xf); + printf("\nEnding value = (%x), Status code = (%x)\n", + *((int *) start_addr), (unsigned long)inb(0x71)); + } +} + +#endif /* DEBUG */ + +/* + * This is used for determining of the command-line should ask the user + * to correct errors. + */ +int fallback = -1; + +char * +skip_to(int after_equal, char *cmdline) +{ + while (*cmdline && (*cmdline != (after_equal ? '=' : ' '))) + cmdline++; + + if (after_equal) + cmdline++; + + while (*cmdline == ' ') + cmdline++; + + return cmdline; +} + + +void +init_cmdline(void) +{ + printf(" [ Minimal BASH-like line editing is supported. For the first word, TAB + lists possible command completions. Anywhere else TAB lists the possible + completions of a device/filename. ESC at any time exits. ]\n"); +} + + +#ifdef DEBUG +char commands[] = + " Possible commands are: \"pause= ...\", \"uppermem= \", \"root= \", + \"rootnoverify= \", \"chainloader= \", \"kernel= ...\", + \"testload= \", \"syscmd= \", \"displaymem\", \"probemps\", + \"module= ...\", \"modulenounzip= ...\", \"makeactive\", \"boot\", and + \"install= [d] [p] []\"\n"; +#else /* DEBUG */ +char commands[] = + " Possible commands are: \"pause= ...\", \"uppermem= \", \"root= \", + \"rootnoverify= \", \"chainloader= \", \"kernel= ...\", + \"module= ...\", \"modulenounzip= ...\", \"makeactive\", \"boot\", and + \"install= [d] [p] []\"\n"; +#endif /* DEBUG */ + +#ifdef DEBUG +static void +debug_fs_print_func(int sector) +{ + printf("[%d]", sector); +} +#endif /* DEBUG */ + + +static int installaddr, installlist, installsect; + +static void +debug_fs_blocklist_func(int sector) +{ +#ifdef DEBUG + printf("[%d]", sector); +#endif /* DEBUG */ + + if (*((unsigned long *)(installlist-4)) + + *((unsigned short *)installlist) != sector + || installlist == BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4) + { + installlist -= 8; + + if (*((unsigned long *)(installlist-8))) + errnum = ERR_WONT_FIT; + else + { + *((unsigned short *)(installlist+2)) = (installaddr >> 4); + *((unsigned long *)(installlist-4)) = sector; + } + } + + *((unsigned short *)installlist) += 1; + installsect = sector; + installaddr += 512; +} + + +int +enter_cmdline(char *script, char *heap) +{ + int bootdev, cmd_len, type = 0, run_cmdline = 1, have_run_cmdline = 0; +#ifdef DEBUG + int mptest = 0; +#endif /* DEBUG */ + char *cur_heap = heap, *cur_entry = script, *old_entry; + + /* initialization */ + saved_drive = boot_drive; + saved_partition = install_partition; + current_drive = 0xFF; + errnum = 0; + + /* restore memory probe state */ + mbi.mem_upper = saved_mem_upper; + if (mem_map) + mbi.flags |= MB_INFO_MEM_MAP; + + /* XXX evil hack !! */ + bootdev = bsd_bootdev(); + + if (!script) + { + init_page(); + init_cmdline(); + } + +restart: + if (script) + { + if (errnum) + { + if (fallback != -1) + return 0; + + print_error(); + run_cmdline = 1; + if (!have_run_cmdline) + { + have_run_cmdline = 1; + putchar('\n'); + init_cmdline(); + } + } + else + { + run_cmdline = 0; + + /* update position in the boot script */ + old_entry = cur_entry; + while (*(cur_entry++)); + + /* copy to work area */ + bcopy(old_entry, cur_heap, ((int)cur_entry) - ((int)old_entry)); + + printf("%s\n", old_entry); + } + } + else + { + cur_heap[0] = 0; + print_error(); + } + + if (run_cmdline && get_cmdline("command> ", commands, cur_heap, 2048)) + return 1; + + if (strcmp("boot", cur_heap) == 0 || (script && !*cur_heap)) + { + if ((type == 'f') | (type == 'n')) + bsd_boot(type, bootdev); + if (type == 'l') + linux_boot(); + + if (type == 'c') + { + gateA20(0); + boot_drive = saved_drive; + chain_stage1(0, BOOTSEC_LOCATION, BOOTSEC_LOCATION-16); + } + + if (!type) + { + printf(" Error, cannot boot unless kernel loaded.\n"); + + if (fallback != -1) + return 0; + + if (script) + { + printf("Press any key to continue..."); + getc(); + return 1; + } + else + goto restart; + } + + /* this is the final possibility */ + multi_boot((int)entry_addr, (int)(&mbi)); + } + + /* get clipped command-line */ + cur_cmdline = skip_to(1, cur_heap); + cmd_len = 0; + while (cur_cmdline[cmd_len++]); + + if (strcmp("chainloader", cur_heap) < 1) + { + if (open(cur_cmdline) && (read(BOOTSEC_LOCATION, SECTOR_SIZE) + == SECTOR_SIZE) + && (*((unsigned short *) (BOOTSEC_LOCATION+BOOTSEC_SIG_OFFSET)) + == BOOTSEC_SIGNATURE)) + type = 'c'; + else if (!errnum) + { + errnum = ERR_EXEC_FORMAT; + type = 0; + } + } + else if (strcmp("pause", cur_heap) < 1) + { + if (getc() == 27) + return 1; + } + else if (strcmp("uppermem", cur_heap) < 1) + { + if (safe_parse_maxint(&cur_cmdline, (int *)&(mbi.mem_upper))) + mbi.flags &= ~MB_INFO_MEM_MAP; + } + else if (strcmp("root", cur_heap) < 1) + { + set_device(cur_cmdline); + + /* this will respond to any "rootn" command, + but that's OK */ + if (!errnum && (cur_heap[4] == 'n' || open_device() + || errnum == ERR_FSYS_MOUNT)) + { + errnum = 0; + saved_partition = current_partition; + saved_drive = current_drive; + + if (cur_heap[4] != 'n') + { + /* XXX evil hack !! */ + bootdev = bsd_bootdev(); + + print_fsys_type(); + } + else + current_drive = -1; + } + } + else if (strcmp("kernel", cur_heap) < 1) + { + /* make sure it's at the beginning of the boot heap area */ + bcopy(cur_heap, heap, cmd_len + (((int)cur_cmdline) - ((int)cur_heap))); + cur_cmdline = heap + (((int)cur_cmdline) - ((int)cur_heap)); + cur_heap = heap; + if (type = load_image()) + cur_heap = cur_cmdline + cmd_len; + } + else if (strcmp("module", cur_heap) < 1) + { + if (type == 'm') + { +#ifndef NO_DECOMPRESSION + /* this will respond to any "modulen" command, + but that's OK */ + if (cur_heap[6] = 'n') + no_decompression = 1; +#endif /* NO_DECOMPRESSION */ + + if (load_module()) + cur_heap = cur_cmdline + cmd_len; + +#ifndef NO_DECOMPRESSION + no_decompression = 0; +#endif /* NO_DECOMPRESSION */ + } + else + errnum = ERR_NEED_KERNEL; + } + else if (strcmp("install", cur_heap) < 1) + { + char *stage1_file = cur_cmdline, *dest_dev, *file, *addr, *config_file; + char buffer[SECTOR_SIZE], old_sect[SECTOR_SIZE]; + int i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4, new_drive = 0xFF; + + dest_dev = skip_to(0, stage1_file); + if (*dest_dev == 'd') + { + new_drive = 0; + dest_dev = skip_to(0, dest_dev); + } + file = skip_to(0, dest_dev); + addr = skip_to(0, file); + + if (safe_parse_maxint(&addr, &installaddr) && open(stage1_file) + && read((int)buffer, SECTOR_SIZE) == SECTOR_SIZE + && set_device(dest_dev) && open_partition() + && devread(0, 0, SECTOR_SIZE, (int)old_sect)) + { + int dest_drive = current_drive, dest_geom = buf_geom; + int dest_sector = part_start, i; + +#ifndef NO_DECOMPRESSION + no_decompression = 1; +#endif + + /* copy possible DOS BPB, 59 bytes at byte offset 3 */ + bcopy(old_sect+BOOTSEC_BPB_OFFSET, buffer+BOOTSEC_BPB_OFFSET, + BOOTSEC_BPB_LENGTH); + + /* if for a hard disk, copy possible MBR/extended part table */ + if ((dest_drive & 0x80) && current_partition == 0xFFFFFF) + bcopy(old_sect+BOOTSEC_PART_OFFSET, buffer+BOOTSEC_PART_OFFSET, + BOOTSEC_PART_LENGTH); + + if (*((short *)(buffer+STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION + || (*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET)) + != BOOTSEC_SIGNATURE) + || (!(dest_drive & 0x80) + && (*((unsigned char *) (buffer+BOOTSEC_PART_OFFSET)) == 0x80 + || buffer[BOOTSEC_PART_OFFSET] == 0))) + { + errnum = ERR_BAD_VERSION; + } + else if (open(file)) + { + if (!new_drive) + new_drive = current_drive; + + bcopy(buffer, (char*)BOOTSEC_LOCATION, SECTOR_SIZE); + + *((unsigned char *)(BOOTSEC_LOCATION+STAGE1_FIRSTLIST)) + = new_drive; + *((unsigned short *)(BOOTSEC_LOCATION+STAGE1_INSTALLADDR)) + = installaddr; + + i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4; + while (*((unsigned long *)i)) + { + if (i < BOOTSEC_LOCATION+STAGE1_FIRSTLIST-256 + || (*((int *)(i-4)) & 0x80000000) + || *((unsigned short *)i) >= 0xA00 + || *((short *) (i+2)) == 0) + { + errnum = ERR_BAD_VERSION; + break; + } + + *((int *)i) = 0; + *((int *)(i-4)) = 0; + i -= 8; + } + + installlist = BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4; + debug_fs = debug_fs_blocklist_func; + + if (!errnum && read(SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE) + { + if (*((long *)SCRATCHADDR) != 0x8070ea + || (*((short *)(SCRATCHADDR+STAGE2_VER_MAJ_OFFS)) + != COMPAT_VERSION)) + errnum = ERR_BAD_VERSION; + else + { + int write_stage2_sect = 0, stage2_sect = installsect; + char *ptr; + + ptr = skip_to(0, addr); + + if (*ptr == 'p') + { + write_stage2_sect++; + *((long *)(SCRATCHADDR+STAGE2_INSTALLPART)) + = current_partition; + ptr = skip_to(0, ptr); + } + if (*ptr) + { + char *str + = ((char *) (SCRATCHADDR+STAGE2_VER_STR_OFFS)); + + write_stage2_sect++; + while (*(str++)); /* find string */ + while (*(str++) = *(ptr++)); /* do copy */ + } + + read(0x100000, -1); + + buf_track = -1; + + if (!errnum + && (biosdisk(BIOSDISK_SUBFUNC_WRITE, + dest_drive, dest_geom, + dest_sector, 1, (BOOTSEC_LOCATION>>4)) + || (write_stage2_sect + && biosdisk(BIOSDISK_SUBFUNC_WRITE, + current_drive, buf_geom, + stage2_sect, 1, SCRATCHSEG)))) + errnum = ERR_WRITE; + } + } + + debug_fs = NULL; + } + +#ifndef NO_DECOMPRESSION + no_decompression = 0; +#endif + } + } +#ifdef DEBUG + else if (strcmp("testload", cur_heap) < 1) + { + if (open(cur_cmdline)) + { + int i; + + debug_fs = debug_fs_print_func; + + /* + * Perform filesystem test on the specified file. + */ + + /* read whole file first */ + printf("Whole file: "); + + read(0x100000, -1); + + /* now compare two sections of the file read differently */ + + for (i = 0; i < 0x10ac0; i++) + { + *((unsigned char *)(0x200000+i)) = 0; + *((unsigned char *)(0x300000+i)) = 1; + } + + /* first partial read */ + printf("\nPartial read 1: "); + + filepos = 0; + read(0x200000, 0x7); + read(0x200007, 0x100); + read(0x200107, 0x10); + read(0x200117, 0x999); + read(0x200ab0, 0x10); + read(0x200ac0, 0x10000); + + /* second partial read */ + printf("\nPartial read 2: "); + + filepos = 0; + read(0x300000, 0x10000); + read(0x310000, 0x10); + read(0x310010, 0x7); + read(0x310017, 0x10); + read(0x310027, 0x999); + read(0x3109c0, 0x100); + + printf("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", + *((int *)0x200000), *((int *)0x200004), *((int *)0x200008), + *((int *)0x20000c)); + + printf("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", + *((int *)0x300000), *((int *)0x300004), *((int *)0x300008), + *((int *)0x30000c)); + + for (i = 0; i < 0x10ac0 && *((unsigned char *)(0x200000+i)) + == *((unsigned char *)(0x300000+i)); i++); + + printf("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos); + + debug_fs = NULL; + } + } + else if (strcmp("syscmd", cur_heap) < 1) + { + switch(cur_cmdline[0]) + { + case 'F': + if (debug_fs) + { + debug_fs = NULL; + printf(" Filesystem tracing is now off\n"); + } + else + { + debug_fs = debug_fs_print_func; + printf(" Filesystem tracing if now on\n"); + } + break; + case 'R': + { + char *ptr = cur_cmdline+1; + int myaddr; + if (safe_parse_maxint(&ptr, &myaddr)) + printf("0x%x: 0x%x", myaddr, *((unsigned *)myaddr)); + } + break; + case 'r': + if (mptest) + { + list_regs(-1); + break; + } + case 'p': + if (mptest) + { + copy_patch_code(); + break; + } + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (mptest) + { + int j = cur_cmdline[0] - '0'; + switch (cur_cmdline[1]) + { + case 'i': + send_init(j); + break; + case 's': + send_startup(j); + break; + case 'r': + list_regs(j); + break; + case 'b': + boot_cpu(j); + } + break; + } + default: + printf("Bad subcommand, try again please\n"); + } + } + else if (strcmp("probemps", cur_heap) == 0) + { + apic_addr = 0xFEE00000; + + if (mptest = probe_mp_table()) + printf("APIC test (%x), SPIV test(%x)\n", + *((volatile unsigned long *) (apic_addr+0x30)), + *((volatile unsigned long *) (apic_addr+0xf0))); + else + printf("No MPS information found\n"); + } + else if (strcmp("displaymem", cur_heap) == 0) + { + if (get_eisamemsize() != -1) + printf(" EISA Memory BIOS Interface is present\n"); + if (get_mem_map(SCRATCHADDR, 0) != 0 || *((int *) SCRATCHADDR) != 0) + printf(" Address Map BIOS Interface is present\n"); + + printf(" Lower memory: %uK, Upper memory (to first chipset hole): %uK\n", + mbi.mem_lower, mbi.mem_upper); + + if (mbi.flags & MB_INFO_MEM_MAP) + { + struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr; + int end_addr = mbi.mmap_addr + mbi.mmap_length; + + printf(" [Address Range Descriptor entries immediately follow (values are 64-bit)]\n"); + while (end_addr > (int)map) + { + char *str; + + if (map->Type == MB_ARD_MEMORY) + str = "Usable RAM"; + else + str = "Reserved"; + printf(" %s: Base Address: 0x%x X 4GB + 0x%x, + Length: %u X 4GB + %u bytes\n", + str, map->BaseAddrHigh, map->BaseAddrLow, + map->LengthHigh, map->LengthLow); + + map = ((struct AddrRangeDesc *) (((int)map) + 4 + map->size)); + } + } + } +#endif /* DEBUG */ + else if (strcmp("makeactive", cur_heap) == 0) + make_saved_active(); + else if (*cur_heap && *cur_heap != ' ') + errnum = ERR_UNRECOGNIZED; + + goto restart; +} + diff --git a/shared_src/common.c b/shared_src/common.c new file mode 100644 index 000000000..b2d22d690 --- /dev/null +++ b/shared_src/common.c @@ -0,0 +1,199 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#define _COMMON_C + +#include "shared.h" + + +/* + * Shared BIOS/boot data. + */ + +struct multiboot_info mbi; +unsigned long saved_drive; +unsigned long saved_partition; +unsigned long saved_mem_upper; +int mem_map = 0; + +/* + * Error code stuff. + */ + +int errnum = 0; + +#ifndef NO_FANCY_STUFF + +char *err_list[] = +{ + 0, + "Selected item won\'t fit into memory", + "Selected disk doesn\'t exist", + "Disk read error", + "Disk write error", + "Disk geometry error", + "Attempt to access block outside partition", + "Partition table invalid or corrupt", + "No such partition", + "Bad filename (must be absolute pathname or blocklist)", + "Bad file or directory type", + "File not found", + "Cannot mount selected partition", + "Inconsistent filesystem structure", + "Filesystem compatibility error, can\'t read whole file", + "Error while parsing number", + "Device string unrecognizable", + "Invalid device requested", + "Invalid or unsupported executable format", + "Loading below 1MB is not supported", + "Unsupported Multiboot features requested", + "Unknown boot failure", + "Must load Multiboot kernel before modules", + "Unrecognized command", + "Bad or incompatible header on compressed file", + "Bad or corrupt data while decompressing file", + "Bad or corrupt version of stage1/stage2", + 0 +}; + + +/* static for BIOS memory map fakery */ +static struct AddrRangeDesc fakemap[3] = +{ + { 20, 0, 0, 0, 0, MB_ARD_MEMORY }, + { 20, 0x100000, 0, 0, 0, MB_ARD_MEMORY }, + { 20, 0x1000000, 0, 0, 0, MB_ARD_MEMORY } +}; +#endif /* NO_FANCY_STUFF */ + + +/* + * This queries for BIOS information. + */ + +void +init_bios_info(void) +{ + /* + * Get information from BIOS on installed RAM. + */ + + mbi.mem_lower = get_memsize(0); + mbi.mem_upper = get_memsize(1); + +#ifndef NO_FANCY_STUFF + /* + * We need to call this somewhere before trying to put data + * above 1 MB, since without calling it, address line 20 will be wired + * to 0. Not too desirable. + */ + + gateA20(1); + + /* + * The "mem_upper" variable only recognizes upper memory in the + * first memory region. If there are multiple memory regions, + * the rest are reported to a Multiboot-compliant OS, but otherwise + * unused by GRUB. + */ + + { + int cont = 0, mem1, mem2, addr; + + mbi.mmap_addr = (addr = (((int) end) & ~3) + 4); + mbi.mmap_length = 0; + + do + { + cont = get_mem_map(addr, cont); + + if ( ! *((int *)addr) ) + break; + + /* + * This is to get the upper memory up to the first memory + * hole into the "mbi.mem_upper" element, for OS's that + * don't care about the memory map, but might care about + * RAM above 64MB. + */ + if (((struct AddrRangeDesc *)addr)->BaseAddrLow == 0x100000 + && ((struct AddrRangeDesc *)addr)->BaseAddrHigh == 0 + && ((struct AddrRangeDesc *)addr)->Type == MB_ARD_MEMORY) + { + /* limit to 4G, as most OS's would probably break with more */ + + if (!((struct AddrRangeDesc *)addr)->LengthHigh) + mbi.mem_upper = ((struct AddrRangeDesc *)addr)->LengthLow >> 10; + else + mbi.mem_upper = 0x3FBFC0; /* 4G - 1M - 64K */ + } + + mbi.mmap_length += *((int *)addr) + 4; + addr += *((int *)addr) + 4; + + mem_map++; + } + while (cont); + + if (!mem_map && (mem1 = get_eisamemsize()) != -1) + { + mem2 = mem1 >> 16; + mem1 &= 0xFFFF; + mbi.mem_upper = mem1; + + if (!mem2 || (mem1 == 0x3c00)) + mbi.mem_upper += (mem2 << 6); + else + { + /* XXX should I do this at all ??? */ + + mbi.mmap_addr = (int)fakemap; + mbi.mmap_length = sizeof(fakemap); + fakemap[0].LengthLow = (mbi.mem_lower << 10); + fakemap[1].LengthLow = (mem1 << 10); + fakemap[2].LengthLow = (mem2 << 16); + mem_map++; + } + } + } + + saved_mem_upper = mbi.mem_upper; + + /* + * Initialize other Multiboot Info flags. + */ + + mbi.flags = MB_INFO_MEMORY | MB_INFO_CMDLINE | MB_INFO_BOOTDEV; + +#endif /* NO_FANCY_STUFF */ + + /* + * Set boot drive and partition. + */ + + saved_drive = boot_drive; + saved_partition = install_partition; + + /* + * Start main routine here. + */ + + cmain(); +} + diff --git a/shared_src/defs.h b/shared_src/defs.h new file mode 100644 index 000000000..65d639894 --- /dev/null +++ b/shared_src/defs.h @@ -0,0 +1,93 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Common definitions for Berkeley Fast File System. + */ + +/* + * Compatibility definitions for disk IO. + */ + +/* + * Disk devices do all IO in 512-byte blocks. + */ +#define DEV_BSIZE 512 + +/* + * Conversion between bytes and disk blocks. + */ +#define btodb(byte_offset) ((byte_offset) >> 9) +#define dbtob(block_number) ((block_number) << 9) + +/* + * Compatibility definitions for old type names. + */ + +typedef unsigned char u_char; /* unsigned char */ +typedef unsigned short u_short; /* unsigned short */ +typedef unsigned int u_int; /* unsigned int */ + +typedef struct _quad_ { + unsigned int val[2]; /* 2 int values make... */ +} quad; /* an 8-byte item */ + +typedef unsigned int time_t; /* an unsigned int */ +typedef unsigned int daddr_t; /* an unsigned int */ +typedef unsigned int off_t; /* another unsigned int */ + +typedef unsigned short uid_t; +typedef unsigned short gid_t; +typedef unsigned int ino_t; + +#define NBBY 8 + +/* + * The file system is made out of blocks of at most MAXBSIZE units, + * with smaller units (fragments) only in the last direct block. + * MAXBSIZE primarily determines the size of buffers in the buffer + * pool. It may be made larger without any effect on existing + * file systems; however, making it smaller may make some file + * systems unmountable. + * + * Note that the disk devices are assumed to have DEV_BSIZE "sectors" + * and that fragments must be some multiple of this size. + */ +#define MAXBSIZE 8192 +#define MAXFRAG 8 + +/* + * MAXPATHLEN defines the longest permissible path length + * after expanding symbolic links. + * + * MAXSYMLINKS defines the maximum number of symbolic links + * that may be expanded in a path name. It should be set + * high enough to allow all legitimate uses, but halt infinite + * loops reasonably quickly. + */ + +#define MAXPATHLEN 1024 +#define MAXSYMLINKS 8 + diff --git a/shared_src/dir.h b/shared_src/dir.h new file mode 100644 index 000000000..208df5cef --- /dev/null +++ b/shared_src/dir.h @@ -0,0 +1,142 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)dir.h 7.6 (Berkeley) 5/9/89 + */ + +#ifndef _BOOT_UFS_DIR_H_ +#define _BOOT_UFS_DIR_H_ + +/* + * A directory consists of some number of blocks of DIRBLKSIZ + * bytes, where DIRBLKSIZ is chosen such that it can be transferred + * to disk in a single atomic operation (e.g. 512 bytes on most machines). + * + * Each DIRBLKSIZ byte block contains some number of directory entry + * structures, which are of variable length. Each directory entry has + * a struct direct at the front of it, containing its inode number, + * the length of the entry, and the length of the name contained in + * the entry. These are followed by the name padded to a 4 byte boundary + * with null bytes. All names are guaranteed null terminated. + * The maximum length of a name in a directory is MAXNAMLEN. + * + * The macro DIRSIZ(dp) gives the amount of space required to represent + * a directory entry. Free space in a directory is represented by + * entries which have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes + * in a directory block are claimed by the directory entries. This + * usually results in the last entry in a directory having a large + * dp->d_reclen. When entries are deleted from a directory, the + * space is returned to the previous entry in the same directory + * block by increasing its dp->d_reclen. If the first entry of + * a directory block is free, then its dp->d_ino is set to 0. + * Entries other than the first in a directory do not normally have + * dp->d_ino set to 0. + */ +#define DIRBLKSIZ DEV_BSIZE +#define MAXNAMLEN 255 + +struct direct { + u_int d_ino; /* inode number of entry */ + u_short d_reclen; /* length of this record */ + u_short d_namlen; /* length of string in d_name */ + char d_name[MAXNAMLEN + 1]; /* name with length <= MAXNAMLEN */ +}; + +/* + * The DIRSIZ macro gives the minimum record length which will hold + * the directory entry. This requires the amount of space in struct direct + * without the d_name field, plus enough space for the name with a terminating + * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. + */ +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) + +#ifdef KERNEL +/* + * Template for manipulating directories. + * Should use struct direct's, but the name field + * is MAXNAMLEN - 1, and this just won't do. + */ +struct dirtemplate { + u_int dot_ino; + short dot_reclen; + short dot_namlen; + char dot_name[4]; /* must be multiple of 4 */ + u_int dotdot_ino; + short dotdot_reclen; + short dotdot_namlen; + char dotdot_name[4]; /* ditto */ +}; +#endif + +/* + * The following information should be obtained from + * and is provided solely (and temporarily) for backward compatibility. + */ +#ifndef KERNEL +#define d_fileno d_ino /* compatibility with POSIX */ +#ifndef DEV_BSIZE +#define DEV_BSIZE 512 +#endif +/* + * Definitions for library routines operating on directories. + */ +typedef struct _dirdesc { + int dd_fd; + int dd_loc; + int dd_size; + char dd_buf[DIRBLKSIZ]; +} DIR; + +#define dirfd(dirp) ((dirp)->dd_fd) + +#ifndef NULL +#define NULL 0 +#endif +extern DIR *opendir(); +extern struct direct *readdir(); +extern int telldir(); +extern void seekdir(); +#define rewinddir(dirp) seekdir((dirp), (long)0) +extern void closedir(); +#endif /* not KERNEL */ +#endif /* _BOOT_UFS_DIR_H_ */ diff --git a/shared_src/disk_inode.h b/shared_src/disk_inode.h new file mode 100644 index 000000000..e0f49ea34 --- /dev/null +++ b/shared_src/disk_inode.h @@ -0,0 +1,101 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)inode.h 7.5 (Berkeley) 7/3/89 + */ + +#ifndef _BOOT_UFS_DISK_INODE_H_ +#define _BOOT_UFS_DISK_INODE_H_ + +/* + * The I node is the focus of all file activity in the BSD Fast File System. + * There is a unique inode allocated for each active file, + * each current directory, each mounted-on file, text file, and the root. + * An inode is 'named' by its dev/inumber pair. (iget/iget.c) + * Data in icommon is read in from permanent inode on volume. + */ + +#define FFS_NDADDR 12 /* direct addresses in inode */ +#define FFS_NIADDR 3 /* indirect addresses in inode */ + +#define FFS_MAX_FASTLINK_SIZE ((FFS_NDADDR + FFS_NIADDR) * sizeof(daddr_t)) + +struct icommon { + u_short ic_mode; /* 0: mode and type of file */ + short ic_nlink; /* 2: number of links to file */ + uid_t ic_uid; /* 4: owner's user id */ + gid_t ic_gid; /* 6: owner's group id */ + quad ic_size; /* 8: number of bytes in file */ + time_t ic_atime; /* 16: time last accessed */ + int ic_atspare; + time_t ic_mtime; /* 24: time last modified */ + int ic_mtspare; + time_t ic_ctime; /* 32: last time inode changed */ + int ic_ctspare; + union { + struct { + daddr_t Mb_db[FFS_NDADDR]; /* 40: disk block addresses */ + daddr_t Mb_ib[FFS_NIADDR]; /* 88: indirect blocks */ + } ic_Mb; + char ic_Msymlink[FFS_MAX_FASTLINK_SIZE]; + /* 40: symbolic link name */ + } ic_Mun; +#define ic_db ic_Mun.ic_Mb.Mb_db +#define ic_ib ic_Mun.ic_Mb.Mb_ib +#define ic_symlink ic_Mun.ic_Msymlink + int ic_flags; /* 100: status, currently unused */ + int ic_blocks; /* 104: blocks actually held */ + int ic_gen; /* 108: generation number */ + int ic_spare[4]; /* 112: reserved, currently unused */ +} i_ic; + +/* + * Same structure, but on disk. + */ +struct dinode { + union { + struct icommon di_com; + char di_char[128]; + } di_un; +}; +#define di_ic di_un.di_com + +#endif /* _BOOT_UFS_DISK_INODE_H_ */ diff --git a/shared_src/disk_inode_ffs.h b/shared_src/disk_inode_ffs.h new file mode 100644 index 000000000..07aaf9b99 --- /dev/null +++ b/shared_src/disk_inode_ffs.h @@ -0,0 +1,101 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)inode.h 7.5 (Berkeley) 7/3/89 + */ + +#ifndef _BOOT_UFS_DISK_INODE_FFS_H_ +#define _BOOT_UFS_DISK_INODE_FFS_H_ + +#define NDADDR FFS_NDADDR +#define NIADDR FFS_NIADDR + +#define MAX_FASTLINK_SIZE FFS_MAX_FASTLINK_SIZE + +#define IC_FASTLINK 0x0001 /* Symbolic link in inode */ + +#define i_mode ic_mode +#define i_nlink ic_nlink +#define i_uid ic_uid +#define i_gid ic_gid +#if BYTE_MSF +#define i_size ic_size.val[1] +#else /* BYTE_LSF */ +#define i_size ic_size.val[0] +#endif +#define i_db ic_db +#define i_ib ic_ib +#define i_atime ic_atime +#define i_mtime ic_mtime +#define i_ctime ic_ctime +#define i_blocks ic_blocks +#define i_rdev ic_db[0] +#define i_symlink ic_symlink +#define i_flags ic_flags +#define i_gen ic_gen + +/* modes */ +#define IFMT 0xf000 /* type of file */ +#define IFCHR 0x2000 /* character special */ +#define IFDIR 0x4000 /* directory */ +#define IFBLK 0x6000 /* block special */ +#define IFREG 0x8000 /* regular */ +#define IFLNK 0xa000 /* symbolic link */ +#define IFSOCK 0xc000 /* socket */ + + +#define ISUID 0x0800 /* set user id on execution */ +#define ISGID 0x0400 /* set group id on execution */ +#define ISVTX 0x0200 /* save swapped text even after use */ +#define IREAD 0x0100 /* read, write, execute permissions */ +#define IWRITE 0x0080 +#define IEXEC 0x0040 + +#ifdef EEK +#define f_fs u.ffs.ffs_fs +#define i_ic u.ffs.ffs_ic +#define f_nindir u.ffs.ffs_nindir +#define f_blk u.ffs.ffs_blk +#define f_blksize u.ffs.ffs_blksize +#define f_blkno u.ffs.ffs_blkno +#endif /* EEK */ + +#endif _BOOT_UFS_DISK_INODE_FFS_H_ diff --git a/shared_src/disk_io.c b/shared_src/disk_io.c new file mode 100644 index 000000000..572f2ac31 --- /dev/null +++ b/shared_src/disk_io.c @@ -0,0 +1,1056 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#define _DISK_IO_C + +#include "shared.h" + +#include "filesys.h" + +/* XXX for evil hack */ +#include "freebsd.h" + +#ifndef NO_FANCY_STUFF +/* instrumentation variables */ +void (*debug_fs)(int) = NULL; +void (*debug_fs_func)(int) = NULL; +#endif /* NO_FANCY_STUFF */ + +/* these have the same format as "boot_drive" and "install_partition", but + are meant to be working values */ +unsigned long current_drive = 0xFF; +unsigned long current_partition; + +/* + * Global variables describing details of the filesystem + */ + +/* XXX BSD evil hack */ +int bsd_evil_hack; + +/* filesystem type */ +int fsys_type = NUM_FSYS; +#ifndef NO_BLOCK_FILES +int block_file = 0; +#endif /* NO_BLOCK_FILES */ + +/* these are the translated numbers for the open partition */ +long part_start; +long part_length; + +int current_slice; + +/* disk buffer parameters */ +int buf_drive = -1; +int buf_track; +int buf_geom; + +/* filesystem common variables */ +int filepos; +int filemax; + + +int +rawread(int drive, int sector, int byte_offset, int byte_len, int addr) +{ + int slen = (byte_offset+byte_len+511)/SECTOR_SIZE; + + if (byte_len <= 0) + return 1; + + while (byte_len > 0 && !errnum) + { + int soff, num_sect, bufaddr, track, size = byte_len; + + /* + * Check track buffer. If it isn't valid or it is from the + * wrong disk, then reset the disk geometry. + */ + if (buf_drive != drive) + { + buf_geom = get_diskinfo(drive); + buf_drive = drive; + buf_track = -1; + } + + if (buf_geom == 0) + { + errnum = ERR_NO_DISK; + return 0; + } + + /* Get first sector of track */ + soff = sector % SECTORS(buf_geom); + track = sector - soff; + num_sect = SECTORS(buf_geom) - soff; + bufaddr = BUFFERADDR + (soff * SECTOR_SIZE) + byte_offset; + + if (track != buf_track) + { + int bios_err, read_start = track, read_len = SECTORS(buf_geom); + + /* + * If there's more than one read in this entire loop, then + * only make the earlier reads for the portion needed. This + * saves filling the buffer with data that won't be used! + */ + if (slen > num_sect) + { + read_start = sector; + read_len = num_sect; + bufaddr = BUFFERADDR + byte_offset; + } + + if (bios_err = biosdisk(BIOSDISK_SUBFUNC_READ, drive, buf_geom, + read_start, read_len, BUFFERSEG)) + { + buf_track = -1; + + if (bios_err == BIOSDISK_ERROR_GEOMETRY) + errnum = ERR_GEOM; + else + { + /* + * If there was an error, try to load only the + * required sector(s) rather than failing completely. + */ + if (slen > num_sect + || biosdisk(BIOSDISK_SUBFUNC_READ, drive, buf_geom, + sector, slen, BUFFERSEG)) + errnum = ERR_READ; + + bufaddr = BUFFERSEG + byte_offset; + } + } + else + buf_track = track; + } + +#ifndef NO_FANCY_STUFF + /* + * Instrumentation to tell which sectors were read and used. + */ + if (debug_fs && debug_fs_func) + { + int sector_end = sector + ((num_sect < slen) ? num_sect : slen); + int sector_num = sector; + + while (sector_num < sector_end) + (*debug_fs_func)(sector_num++); + } +#endif /* NO_FANCY_STUFF */ + + if (size > ((num_sect * SECTOR_SIZE) - byte_offset)) + size = (num_sect * SECTOR_SIZE) - byte_offset; + + bcopy((char *)bufaddr, (char *)addr, size); + + addr += size; + byte_len -= size; + sector += num_sect; + slen -= num_sect; + byte_offset = 0; + } + + return (!errnum); +} + + +int +devread(int sector, int byte_offset, int byte_len, int addr) +{ + /* + * Check partition boundaries + */ + if (sector < 0 + || (sector + ((byte_offset+byte_len-1)/SECTOR_SIZE)) >= part_length) + { + errnum = ERR_OUTSIDE_PART; + return 0; + } + + /* + * Get the read to the beginning of a partition. + */ + while (byte_offset >= SECTOR_SIZE) + { + byte_offset -= SECTOR_SIZE; + sector++; + } + +#if !defined(NO_FANCY_STUFF) && defined(DEBUG) + if (debug_fs) + printf("<%d, %d, %d>", sector, byte_offset, byte_len); +#endif /* !NO_FANCY_STUFF && DEBUG */ + + /* + * Call "rawread", which is very similar, but: + * + * -- It takes an extra parameter, the drive number. + * -- It requires that "sector" is relative to the beginning + * of the disk. + * -- It doesn't handle offsets of more than 511 bytes into the + * sector. + */ + return rawread(current_drive, part_start+sector, byte_offset, + byte_len, addr); +} + + +int +sane_partition(void) +{ + if ( !(current_partition & 0xFF000000uL) + && (current_drive & 0xFFFFFF7F) < 8 + && (current_partition & 0xFF) == 0xFF + && ( (current_partition & 0xFF00) == 0xFF00 + || (current_partition & 0xFF00) < 0x800 ) + && ( (current_partition >> 16) == 0xFF + || (current_drive & 0x80) ) ) + return 1; + + errnum = ERR_DEV_VALUES; + return 0; +} + + +static void +attempt_mount(void) +{ + for ( fsys_type = 0; fsys_type < NUM_FSYS + && (*(fsys_table[fsys_type].mount_func))() != 1; fsys_type++); + + if (fsys_type == NUM_FSYS && errnum == ERR_NONE) + errnum = ERR_FSYS_MOUNT; +} + + +#ifndef NO_FANCY_STUFF +int +make_saved_active(void) +{ + if (saved_drive & 0x80) + { + int part = saved_partition >> 16; + + if (part > 3) + { + errnum = ERR_NO_PART; + return 0; + } + + if (!rawread(saved_drive, 0, 0, SECTOR_SIZE, SCRATCHADDR)) + return 0; + + if (PC_SLICE_FLAG(SCRATCHADDR, part) != PC_SLICE_FLAG_BOOTABLE) + { + int i; + + for (i = 0; i < 4; i++) + PC_SLICE_FLAG(SCRATCHADDR, i) = 0; + + PC_SLICE_FLAG(SCRATCHADDR, part) = PC_SLICE_FLAG_BOOTABLE; + + buf_track = -1; + + if (biosdisk(BIOSDISK_SUBFUNC_WRITE, saved_drive, buf_geom, + 0, 1, SCRATCHSEG)) + { + errnum = ERR_WRITE; + return 0; + } + } + } + + return 1; +} + + +static void +check_and_print_mount(void) +{ + attempt_mount(); + if (errnum == ERR_FSYS_MOUNT) + errnum = ERR_NONE; + if (!errnum) + print_fsys_type(); + print_error(); +} +#endif /* NO_FANCY_STUFF */ + + +static int +check_BSD_parts(int flags) +{ + char label_buf[SECTOR_SIZE]; + int part_no, got_part = 0; + + if ( part_length < (BSD_LABEL_SECTOR+1) ) + { + errnum = ERR_BAD_PART_TABLE; + return 0; + } + + if (!rawread(current_drive, part_start + BSD_LABEL_SECTOR, + 0, SECTOR_SIZE, (int) label_buf)) + return 0; + + if ( BSD_LABEL_CHECK_MAG(label_buf) ) + { + for (part_no = 0; part_no < BSD_LABEL_NPARTS(label_buf); part_no++) + { + if (BSD_PART_TYPE(label_buf, part_no)) + { + /* XXX should do BAD144 sector remapping setup here */ + + current_slice = ((BSD_PART_TYPE(label_buf, part_no) << 8) + | PC_SLICE_TYPE_BSD); + part_start = BSD_PART_START(label_buf, part_no); + part_length = BSD_PART_LENGTH(label_buf, part_no); + +#ifndef NO_FANCY_STUFF + if (flags) + { + if (!got_part) + { + printf("[BSD sub-partitions immediately follow]\n"); + got_part = 1; + } + printf(" BSD Partition num: \'%c\', ", part_no + 'a'); + check_and_print_mount(); + } + else +#endif /* NO_FANCY_STUFF */ + if (part_no == ((current_partition >> 8) & 0xFF)) + break; + } + } + + if (part_no >= BSD_LABEL_NPARTS(label_buf) && !got_part) + { + errnum = ERR_NO_PART; + return 0; + } + + if ((current_drive & 0x80) + && BSD_LABEL_DTYPE(label_buf) == DTYPE_SCSI) + bsd_evil_hack = 4; + + return 1; + } + + errnum = ERR_BAD_PART_TABLE; + return 0; +} + + +static int +real_open_partition(int flags) +{ + char mbr_buf[SECTOR_SIZE]; + int i, part_no, slice_no, ext = 0, part_offset = 0; + + /* + * The "rawread" is probably unnecessary here, but it is good to + * know it works. + */ + if ( !sane_partition() + || !rawread(current_drive, 0, 0, SECTOR_SIZE, (int) mbr_buf) ) + return 0; + + bsd_evil_hack = 0; + current_slice = 0; + part_start = 0; + part_length = SECTORS(buf_geom) * HEADS(buf_geom) * CYLINDERS(buf_geom); + + if (current_drive & 0x80) + { + /* + * We're looking at a hard disk + */ + + int ext_offset = 0, part_offset = 0; + part_no = (current_partition >> 16); + slice_no = 0; + + /* if this is the whole disk, return here */ + if (!flags && current_partition == 0xFFFFFFuL) + return 1; + + /* + * Load the current MBR-style PC partition table (4 entries) + */ + while ( slice_no < 255 && ext >= 0 + && (part_no == 0xFF || slice_no <= part_no) + && rawread(current_drive, part_offset, + 0, SECTOR_SIZE, (int) mbr_buf) ) + { + /* + * If the table isn't valid, we can't continue + */ + if ( !PC_MBR_CHECK_SIG(mbr_buf) ) + { + errnum = ERR_BAD_PART_TABLE; + return 0; + } + + ext = -1; + + /* + * Scan table for partitions + */ + for (i = 0; i < PC_SLICE_MAX; i++) + { + current_partition = ((slice_no << 16) + | (current_partition & 0xFFFF)); + current_slice = PC_SLICE_TYPE(mbr_buf, i); + part_start = part_offset + PC_SLICE_START(mbr_buf, i); + part_length = PC_SLICE_LENGTH(mbr_buf, i); + + /* + * Is this PC partition entry valid? + */ + if (current_slice) + { + /* + * Is this an extended partition? + */ + if (current_slice == PC_SLICE_TYPE_EXTENDED) + { + if (ext == -1) + { + ext = i; + } + } +#ifndef NO_FANCY_STUFF + /* + * Display partition information + */ + else if (flags) + { + current_partition |= 0xFFFF; + printf(" Partition num: %d, ", slice_no); + if (current_slice != PC_SLICE_TYPE_BSD) + check_and_print_mount(); + else + check_BSD_parts(1); + errnum = ERR_NONE; + } +#endif /* NO_FANCY_STUFF */ + /* + * If we've found the right partition, we're done + */ + else if (part_no == slice_no + || (part_no == 0xFF + && current_slice == PC_SLICE_TYPE_BSD)) + { + if ((current_partition & 0xFF00) != 0xFF00) + { + if (current_slice == PC_SLICE_TYPE_BSD) + check_BSD_parts(0); + else + errnum = ERR_NO_PART; + } + + ext = -2; + break; + } + } + + /* + * If we're beyond the end of the standard PC partition + * range, change the numbering from one per table entry + * to one per valid entry. + */ + if (slice_no < PC_SLICE_MAX + || (current_slice != PC_SLICE_TYPE_EXTENDED + && current_slice != PC_SLICE_TYPE_NONE)) + slice_no++; + } + + part_offset = ext_offset + PC_SLICE_START(mbr_buf, ext); + if (!ext_offset) + ext_offset = part_offset; + } + } + else + { + /* + * We're looking at a floppy disk + */ + ext = -1; + if ((flags || (current_partition & 0xFF00) != 0xFF00) + && check_BSD_parts(flags)) + ext = -2; + else + { + errnum = 0; + if (!flags) + { + if (current_partition == 0xFFFFFF + || current_partition == 0xFF00FF) + { + current_partition == 0xFFFFFF; + ext = -2; + } + } +#ifndef NO_FANCY_STUFF + else + { + current_partition = 0xFFFFFF; + check_and_print_mount(); + errnum = 0; + } +#endif /* NO_FANCY_STUFF */ + } + } + + if (!flags && (ext != -2) && (errnum == ERR_NONE)) + errnum = ERR_NO_PART; + + if (errnum != ERR_NONE) + return 0; + + return 1; +} + + +int +open_partition(void) +{ + return real_open_partition(0); +} + + +/* XX used for device completion in 'set_device' and 'print_completions' */ +static int incomplete, disk_choice, part_choice; + + +int +set_device(char *device) +{ + int retval = 0; + + incomplete = 0; + disk_choice = 1; + part_choice = 0; + current_drive = saved_drive; + current_partition = 0xFFFFFF; + + if (*device == '(' && *(++device)) + { + if (*device != ',' && *device != ')') + { + char ch = *device; + + if ((*device == 'f' || *device == 'h') + && (device += 2, (*(device-1) != 'd'))) + errnum = ERR_NUMBER_PARSING; + + safe_parse_maxint(&device, (int*)¤t_drive); + + disk_choice = 0; + if (ch == 'h') + current_drive += 0x80; + } + + if (errnum) + return 0; + + if (*device == ')') + { + part_choice = 2; + retval++; + } + if (*device == ',') + { + disk_choice = 0; + part_choice++; + device++; + + if (*device >= '0' && *device <= '9') + { + part_choice++; + current_partition = 0; + + if (!(current_drive & 0x80) + || !safe_parse_maxint(&device, (int*)¤t_partition) + || current_partition > 254) + { + errnum = ERR_DEV_FORMAT; + return 0; + } + + current_partition = (current_partition << 16) + 0xFFFF; + + if (*device == ',' + && *(device+1) >= 'a' && *(device+1) <= 'h') + { + device++; + current_partition = (((*(device++) - 'a') << 8) + | (current_partition & 0xFF00FF)); + } + } + else if (*device >= 'a' && *device <= 'h') + { + part_choice++; + current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF; + } + + if (*device == ')') + { + if (part_choice == 1) + { + current_partition = saved_partition; + part_choice++; + } + + retval++; + } + } + } + + if (retval) + retval = ((int)device) + 1; + else + { + if (!*device) + incomplete = 1; + errnum = ERR_DEV_FORMAT; + } + + return retval; +} + + +/* + * This performs a "mount" on the current device, both drive and partition + * number. + */ + +int +open_device(void) +{ + if (open_partition()) + attempt_mount(); + + if (errnum != ERR_NONE) + return 0; + + return 1; +} + + +#ifndef NO_FANCY_STUFF +int +bsd_bootdev(void) +{ + int i, j; + + if (saved_partition == 0xFFFFFF) + i = 1; + else if ((saved_partition >> 16) == 0xFF) + i = 0; + else + i = (saved_partition >> 16) + 2; + + /* XXX extremely evil hack!!! */ + if (saved_drive & 0x80) + j = bsd_evil_hack; + else + j = 2; + + return MAKEBOOTDEV( j, (i >> 4), (i & 0xF), (saved_drive & 0x79), + ((saved_partition >> 8) & 0xFF) ); +} +#endif /* NO_FANCY_STUFF */ + + +static char * +setup_part(char *filename) +{ + if (*filename == '(') + { + if ( (filename = (char *) set_device(filename)) == (char *)0 ) + { + current_drive = 0xFF; + return 0; + } +#ifndef NO_BLOCK_FILES + if (*filename != '/') + open_partition(); + else +#endif /* NO_BLOCK_FILES */ + open_device(); + } + else if (saved_drive != current_drive + || saved_partition != current_partition + || (*filename == '/' && fsys_type == NUM_FSYS) + || buf_drive == -1) + { + current_drive = saved_drive; + current_partition = saved_partition; + /* allow for the error case of "no filesystem" after the partition + is found. This makes block files work fine on no filesystem */ +#ifndef NO_BLOCK_FILES + if (*filename != '/') + open_partition(); + else +#endif /* NO_BLOCK_FILES */ + open_device(); + } + + if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT)) + return 0; + else + errnum = 0; + + if (!sane_partition()) + return 0; + + return filename; +} + + +#ifndef NO_FANCY_STUFF +/* + * This prints the filesystem type or gives relevant information. + */ + +void +print_fsys_type(void) +{ + printf(" Filesystem type "); + + if (fsys_type != NUM_FSYS) + printf("is %s\n", fsys_table[fsys_type].name); + else + { + printf("unknown, "); + if (current_partition == 0xFFFFFF) + printf("using whole disk\n"); + else + printf("partition type 0x%x\n", current_slice); + } +} + +/* + * This lists the possible completions of a device string, filename, or + * any sane combination of the two. + */ + +void +print_completions(char *filename) +{ + char *ptr = filename; + + if (*filename == '/' || (ptr = (char *)set_device(filename)) || incomplete) + { + errnum = 0; + + if (*filename != '/' && (incomplete || !*ptr)) + { + if (!part_choice) + { + /* disk completions */ + int disk_no, i, j; + + printf(" Possible disks are: "); + + for (i = 0; i < 2; i++) + { + for (j = 0; j < 8; j++) + { + disk_no = (i * 0x80) + j; + if ((disk_choice || disk_no == current_drive) + && get_diskinfo(disk_no)) + printf(" %cd%d", (i ? 'h' : 'f'), j); + } + } + + putchar('\n'); + } + else + { + /* partition completions */ + if (part_choice == 1) + { + printf(" Possible partitions are:\n"); + real_open_partition(1); + } + else + { + if (open_partition()) + check_and_print_mount(); + } + } + } + else if (*ptr == '/') + { + /* filename completions */ + printf(" Possible files are:"); + dir(filename); + } + else + errnum = ERR_BAD_FILENAME; + } + + print_error(); +} +#endif /* NO_FANCY_STUFF */ + + +/* + * This is the generic file open function. + */ + +int +open(char *filename) +{ +#ifndef NO_DECOMPRESSION + compressed_file = 0; +#endif /* NO_DECOMPRESSION */ + + /* if any "dir" function uses/sets filepos, it must + set it to zero before returning if opening a file! */ + filepos = 0; + + if (!(filename = setup_part(filename))) + return 0; + +#ifndef NO_BLOCK_FILES + block_file = 0; +#endif /* NO_BLOCK_FILES */ + + /* XXX to account for partial filesystem implementations! */ + fsmax = MAXINT; + + if (*filename != '/') + { +#ifndef NO_BLOCK_FILES + char *ptr = filename; + int tmp, list_addr = BLK_BLKLIST_START; + filemax = 0; + + while (list_addr < BLK_MAX_ADDR) + { + tmp = 0; + safe_parse_maxint(&ptr, &tmp); + errnum = 0; + + if (*ptr != '+') + { + if ((*ptr && *ptr != '/' && !isspace(*ptr)) + || tmp == 0 || tmp > filemax) + errnum = ERR_BAD_FILENAME; + else + filemax = tmp; + + break; + } + + /* since we use the same filesystem buffer, mark it to + be remounted */ + fsys_type = NUM_FSYS; + + BLK_BLKSTART(list_addr) = tmp; + ptr++; + + if (!safe_parse_maxint(&ptr, &tmp) + || tmp == 0 + || (*ptr && *ptr != ',' && *ptr != '/' && !isspace(*ptr))) + { + errnum = ERR_BAD_FILENAME; + break; + } + + BLK_BLKLENGTH(list_addr) = tmp; + + filemax += (tmp * SECTOR_SIZE); + list_addr += BLK_BLKLIST_INC_VAL; + + if (*ptr != ',') + break; + + ptr++; + } + + if (list_addr < BLK_MAX_ADDR && ptr != filename && !errnum) + { + block_file = 1; + BLK_CUR_FILEPOS = 0; + BLK_CUR_BLKLIST = BLK_BLKLIST_START; + BLK_CUR_BLKNUM = 0; + +#ifndef NO_DECOMPRESSION + return gunzip_test_header(); +#else /* NO_DECOMPRESSION */ + return 1; +#endif /* NO_DECOMPRESSION */ + } +#else /* NO_BLOCK_FILES */ + errnum = ERR_BAD_FILENAME; +#endif /* NO_BLOCK_FILES */ + } + + if (!errnum && fsys_type == NUM_FSYS) + errnum = ERR_FSYS_MOUNT; + + /* set "dir" function to open a file */ + print_possibilities = 0; + + if (!errnum && (*(fsys_table[fsys_type].dir_func))(filename)) + { +#ifndef NO_DECOMPRESSION + return gunzip_test_header(); +#else /* NO_DECOMPRESSION */ + return 1; +#endif /* NO_DECOMPRESSION */ + } + + return 0; +} + + +int +read(int addr, int len) +{ + /* Make sure "filepos" is a sane value */ + if ((filepos < 0) | (filepos > filemax)) + filepos = filemax; + + /* Make sure "len" is a sane value */ + if ((len < 0) | (len > (filemax - filepos))) + len = filemax - filepos; + + /* if target file position is past the end of + the supported/configured filesize, then + there is an error */ + if (filepos+len > fsmax) + { + errnum = ERR_FILELENGTH; + return 0; + } + +#ifndef NO_DECOMPRESSION + if (compressed_file) + return gunzip_read(addr, len); +#endif /* NO_DECOMPRESSION */ + +#ifndef NO_BLOCK_FILES + if (block_file) + { + int size, off, ret = 0; + + while (len && !errnum) + { + /* we may need to look for the right block in the list(s) */ + if (filepos < BLK_CUR_FILEPOS) + { + BLK_CUR_FILEPOS = 0; + BLK_CUR_BLKLIST = BLK_BLKLIST_START; + BLK_CUR_BLKNUM = 0; + } + + /* run BLK_CUR_FILEPOS up to filepos */ + while ( filepos > BLK_CUR_FILEPOS ) + { + if ( (filepos - (BLK_CUR_FILEPOS & ~(SECTOR_SIZE - 1))) + >= SECTOR_SIZE ) + { + BLK_CUR_FILEPOS += SECTOR_SIZE; + BLK_CUR_BLKNUM++; + + if ( BLK_CUR_BLKNUM >= BLK_BLKLENGTH(BLK_CUR_BLKLIST) ) + { + BLK_CUR_BLKLIST += BLK_BLKLIST_INC_VAL; + BLK_CUR_BLKNUM = 0; + } + } + else + BLK_CUR_FILEPOS = filepos; + } + + off = filepos & (SECTOR_SIZE - 1); + size = ( ( BLK_BLKLENGTH(BLK_CUR_BLKLIST) - BLK_CUR_BLKNUM ) + * SECTOR_SIZE ) - off; + if (size > len) + size = len; + +#ifndef NO_FANCY_STUFF + debug_fs_func = debug_fs; +#endif /* NO_FANCY_STUFF */ + + /* read current block and put it in the right place in memory */ + devread(BLK_BLKSTART(BLK_CUR_BLKLIST) + BLK_CUR_BLKNUM, + off, size, addr); + +#ifndef NO_FANCY_STUFF + debug_fs_func = NULL; +#endif /* NO_FANCY_STUFF */ + + len -= size; + filepos += size; + ret += size; + addr += size; + } + + if (errnum) + ret = 0; + + return ret; + } +#endif /* NO_BLOCK_FILES */ + + if (fsys_type == NUM_FSYS) + { + errnum = ERR_FSYS_MOUNT; + return 0; + } + + return (*(fsys_table[fsys_type].read_func))(addr, len); +} + + +int +dir(char *dirname) +{ +#ifndef NO_DECOMPRESSION + compressed_file = 0; +#endif /* NO_DECOMPRESSION */ + + if (!(dirname = setup_part(dirname))) + return 0; + + if (*dirname != '/') + errnum = ERR_BAD_FILENAME; + + if (fsys_type == NUM_FSYS) + errnum = ERR_FSYS_MOUNT; + + if (errnum) + return 0; + + /* set "dir" function to list completions */ + print_possibilities = 1; + + return (*(fsys_table[fsys_type].dir_func))(dirname); +} + diff --git a/shared_src/fat.h b/shared_src/fat.h new file mode 100644 index 000000000..9a08d087e --- /dev/null +++ b/shared_src/fat.h @@ -0,0 +1,114 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +/* + * Defines for the FAT BIOS Parameter Block (embedded in the first block + * of the partition. + */ + +#define FAT_BPB_SIGNATURE 0x29 + +/* is checking for this signature thing even valid? */ +#define FAT_BPB_CHECK_SIG(bpb) \ + (*((unsigned char *) (((int)bpb) + 38)) == FAT_BPB_SIGNATURE) + +#define FAT_BPB_NUM_SECTORS(bpb) \ + ( *((unsigned short *) (((int)bpb) + 19)) ? \ + *((unsigned short *) (((int)bpb) + 19)) : \ + *((unsigned long *) (((int)bpb) + 32)) ) + +#define FAT_BPB_BYTES_PER_SECTOR(bpb) \ + (*((unsigned short *) (((int)bpb) + 11))) +#define FAT_BPB_SECT_PER_CLUST(bpb) \ + (*((unsigned char *) (((int)bpb) + 13))) +#define FAT_BPB_NUM_FAT(bpb) \ + (*((unsigned char *) (((int)bpb) + 16))) + +#define FAT_BPB_RESERVED_SECTORS(bpb) \ + (*((unsigned short *) (((int)bpb) + 14))) +#define FAT_BPB_FAT_SECTORS(bpb) \ + (*((unsigned short *) (((int)bpb) + 22))) +#define FAT_BPB_FAT_START(bpb) FAT_BPB_RESERVED_SECTORS(bpb) + +/* + * This appears to be a MAJOR kludge!! Don't use it if possible... + */ +#define FAT_BPB_HIDDEN_SECTORS(bpb) \ + (*((unsigned long *) (((int)bpb) + 28))) + +#define FAT_BPB_ROOT_DIR_START(bpb) \ + ( FAT_BPB_NUM_FAT(bpb) * FAT_BPB_FAT_SECTORS(bpb) \ + + FAT_BPB_FAT_START(bpb) ) + +#define FAT_BPB_ROOT_DIR_LENGTH(bpb) \ + ( (*((unsigned short *) (((int)bpb) + 17)) + 0xF) >> 4 ) + +#define FAT_BPB_DATA_OFFSET(bpb) \ + ( FAT_BPB_ROOT_DIR_START(bpb) + FAT_BPB_ROOT_DIR_LENGTH(bpb) ) + +#define FAT_BPB_NUM_CLUST(bpb) \ + ( ( FAT_BPB_NUM_SECTORS(bpb) - FAT_BPB_DATA_OFFSET(bpb) ) \ + / FAT_BPB_SECT_PER_CLUST(bpb) ) + +/* + * Defines minimum disk size to be considered a FAT partition + */ + +#define FAT_MIN_NUM_SECTORS 720 /* 360 K disk */ + +/* + * Defines how to differentiate a 12-bit and 16-bit FAT. + */ + +#define FAT_MAX_12BIT_CLUST 4087 /* 4085 + 2 */ + +#define FAT_BPB_FLOPPY_NUM_SECTORS(bpb) \ + ( *((unsigned short *) (((int)bpb) + 19)) \ + && !*((unsigned long *) (((int)bpb) + 32)) \ + && *((unsigned short *) (((int)bpb) + 19)) >= FAT_MIN_NUM_SECTORS \ + && ((*((unsigned short *) (((int)bpb) + 19)) - FAT_BPB_DATA_OFFSET(bpb)) \ + / FAT_BPB_SECT_PER_CLUST(bpb)) < (FAT_BPB_FAT_SECTORS(bpb) * 342) ) + +/* + * Defines for the file "attribute" byte + */ + +#define FAT_ATTRIB_OK_MASK 0x37 +#define FAT_ATTRIB_NOT_OK_MASK 0xC8 +#define FAT_ATTRIB_DIR 0x10 + + +/* + * Defines for FAT directory entries + */ + +#define FAT_DIRENTRY_LENGTH 32 + +#define FAT_DIRENTRY_ATTRIB(entry) \ + (*((unsigned char *) (entry+11))) +#define FAT_DIRENTRY_VALID(entry) \ + ( ((*((unsigned char *) entry)) != 0) \ + & ((*((unsigned char *) entry)) != 0xE5) \ + & !(FAT_DIRENTRY_ATTRIB(entry) & FAT_ATTRIB_NOT_OK_MASK) ) +#define FAT_DIRENTRY_FIRST_CLUSTER(entry) \ + (*((unsigned short *) (entry+26))) +#define FAT_DIRENTRY_FILELENGTH(entry) \ + (*((unsigned long *) (entry+28))) + diff --git a/shared_src/filesys.h b/shared_src/filesys.h new file mode 100644 index 000000000..a62506952 --- /dev/null +++ b/shared_src/filesys.h @@ -0,0 +1,119 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "pc_slice.h" + +#define SECTORS(geom) ( (geom) & 0xFF ) +#define HEADS(geom) ( ( ( (geom) >> 8 ) & 0xFF ) + 1 ) +#define CYLINDERS(geom) ( ( ( (geom) >> 16 ) & 0x3FF ) + 1 ) + +/* + * Default to all functioning filesystems enabled + */ + +#if !( defined(FSYS_FFS) || defined(FSYS_FAT) || defined(FSYS_EXT2FS) ) +#define FSYS_FFS +#define FSYS_FAT +#define FSYS_EXT2FS +#endif + +#ifdef FSYS_FFS +#define FSYS_FFS_NUM 1 +int ffs_mount(void); +int ffs_read(int addr, int len); +int ffs_dir(char *dirname); +#else +#define FSYS_FFS_NUM 0 +#endif + +#ifdef FSYS_FAT +#define FSYS_FAT_NUM 1 +int fat_mount(void); +/* XX FAT filesystem uses block filesystem code for read! */ +int fat_dir(char *dirname); +#ifdef NO_BLOCK_FILES +#undef NO_BLOCK_FILES +#endif /* NO_BLOCK_FILES */ +#else +#define FSYS_FAT_NUM 0 +#endif + +#ifdef FSYS_EXT2FS +#define FSYS_EXT2FS_NUM 1 +int ext2fs_mount(void); +int ext2fs_read(int addr, int len); +int ext2fs_dir(char *dirname); +#else +#define FSYS_EXT2FS_NUM 0 +#endif + +#ifndef NUM_FSYS +#define NUM_FSYS ( FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM ) +#endif + +/* defines for the block filesystem info area */ +#ifndef NO_BLOCK_FILES +#define BLK_CUR_FILEPOS (*((int*)FSYS_BUF)) +#define BLK_CUR_BLKLIST (*((int*)(FSYS_BUF+4))) +#define BLK_CUR_BLKNUM (*((int*)(FSYS_BUF+8))) +#define BLK_MAX_ADDR (FSYS_BUF+0x7FF9) +#define BLK_BLKSTART(l) (*((int*)l)) +#define BLK_BLKLENGTH(l) (*((int*)(l+4))) +#define BLK_BLKLIST_START (FSYS_BUF+12) +#define BLK_BLKLIST_INC_VAL 8 +#endif /* NO_BLOCK_FILES */ + +/* this next part is pretty ugly, but it keeps it in one place! */ + +struct fsys_entry +{ + char *name; + int (*mount_func)(void); + int (*read_func)(int addr, int len); + int (*dir_func)(char *dirname); +}; + +#ifndef _DISK_IO_C + +extern int fsmax; +extern int print_possibilities; +extern struct fsys_entry fsys_table[NUM_FSYS+1]; + +#else + +int fsmax; +int print_possibilities; +struct fsys_entry fsys_table[NUM_FSYS+1] = +{ +#ifdef FSYS_FAT + { "fat", fat_mount, 0, fat_dir }, +#endif +#ifdef FSYS_EXT2FS + { "ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir }, +#endif + /* XX FFS should come last as it's superblock is commonly crossing tracks + on floppies from track 1 to 2, while others only use 1. */ +#ifdef FSYS_FFS + { "ffs", ffs_mount, ffs_read, ffs_dir }, +#endif + { 0, 0, 0, 0 } +}; + +#endif + diff --git a/shared_src/freebsd.h b/shared_src/freebsd.h new file mode 100644 index 000000000..18d564e2a --- /dev/null +++ b/shared_src/freebsd.h @@ -0,0 +1,90 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* command-line parameter defines */ +#define RB_ASKNAME 0x01 /* ask for file name to reboot from */ +#define RB_SINGLE 0x02 /* reboot to single user only */ +#define RB_NOSYNC 0x04 /* dont sync before reboot */ +#define RB_HALT 0x08 /* don't reboot, just halt */ +#define RB_INITNAME 0x10 /* name given for /etc/init (unused) */ +#define RB_DFLTROOT 0x20 /* use compiled-in rootdev */ +#define RB_KDB 0x40 /* give control to kernel debugger */ +#define RB_RDONLY 0x80 /* mount root fs read-only */ +#define RB_DUMP 0x100 /* dump kernel memory before reboot */ +#define RB_MINIROOT 0x200 /* mini-root present in memory at boot time */ +#define RB_CONFIG 0x400 /* invoke user configuration routing */ +#define RB_VERBOSE 0x800 /* print all potentially useful info */ +#define RB_SERIAL 0x1000 /* user serial port as console */ +#define RB_CDROM 0x2000 /* use cdrom as root */ + +#define RB_BOOTINFO 0x80000000 /* have `struct bootinfo *' arg */ + +/* + * Constants for converting boot-style device number to type, + * adaptor (uba, mba, etc), unit number and partition number. + * Type (== major device number) is in the low byte + * for backward compatibility. Except for that of the "magic + * number", each mask applies to the shifted value. + * Format: + * (4) (4) (4) (4) (8) (8) + * -------------------------------- + * |MA | AD| CT| UN| PART | TYPE | + * -------------------------------- + */ +#define B_ADAPTORSHIFT 24 +#define B_CONTROLLERSHIFT 20 +#define B_UNITSHIFT 16 +#define B_PARTITIONSHIFT 8 +#define B_TYPESHIFT 0 + +#define B_DEVMAGIC ((unsigned long)0xa0000000) + +#define MAKEBOOTDEV(type, adaptor, controller, unit, partition) \ + (((type) << B_TYPESHIFT) | ((adaptor) << B_ADAPTORSHIFT) | \ + ((controller) << B_CONTROLLERSHIFT) | ((unit) << B_UNITSHIFT) | \ + ((partition) << B_PARTITIONSHIFT) | B_DEVMAGIC) + + +/* Only change the version number if you break compatibility. */ +#define BOOTINFO_VERSION 1 + +#define N_BIOS_GEOM 8 + +/* + * A zero bootinfo field often means that there is no info available. + * Flags are used to indicate the validity of fields where zero is a + * normal value. + */ +struct bootinfo { + unsigned int bi_version; + unsigned char *bi_kernelname; + struct nfs_diskless *bi_nfs_diskless; + /* End of fields that are always present. */ +#define bi_endcommon bi_n_bios_used + unsigned int bi_n_bios_used; + unsigned long bi_bios_geom[N_BIOS_GEOM]; + unsigned int bi_size; + unsigned char bi_memsizes_valid; + unsigned char bi_pad[3]; + unsigned long bi_basemem; + unsigned long bi_extmem; + unsigned long bi_symtab; + unsigned long bi_esymtab; +}; + diff --git a/shared_src/fs.h b/shared_src/fs.h new file mode 100644 index 000000000..5809ed937 --- /dev/null +++ b/shared_src/fs.h @@ -0,0 +1,455 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ +/* + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * 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. + * + * @(#)fs.h 7.7 (Berkeley) 5/9/89 + */ + +/* + * Each disk drive contains some number of file systems. + * A file system consists of a number of cylinder groups. + * Each cylinder group has inodes and data. + * + * A file system is described by its super-block, which in turn + * describes the cylinder groups. The super-block is critical + * data and is replicated in each cylinder group to protect against + * catastrophic loss. This is done at `newfs' time and the critical + * super-block data does not change, so the copies need not be + * referenced further unless disaster strikes. + * + * For file system fs, the offsets of the various blocks of interest + * are given in the super block as: + * [fs->fs_sblkno] Super-block + * [fs->fs_cblkno] Cylinder group block + * [fs->fs_iblkno] Inode blocks + * [fs->fs_dblkno] Data blocks + * The beginning of cylinder group cg in fs, is given by + * the ``cgbase(fs, cg)'' macro. + * + * The first boot and super blocks are given in absolute disk addresses. + * The byte-offset forms are preferred, as they don't imply a sector size. + */ +#define BBSIZE 8192 +#define SBSIZE 8192 +#define BBOFF ((off_t)(0)) +#define SBOFF ((off_t)(BBOFF + BBSIZE)) +#define BBLOCK ((daddr_t)(0)) +#define SBLOCK ((daddr_t)(BBLOCK + BBSIZE / DEV_BSIZE)) + +/* + * Addresses stored in inodes are capable of addressing fragments + * of `blocks'. File system blocks of at most size MAXBSIZE can + * be optionally broken into 2, 4, or 8 pieces, each of which is + * addressible; these pieces may be DEV_BSIZE, or some multiple of + * a DEV_BSIZE unit. + * + * Large files consist of exclusively large data blocks. To avoid + * undue wasted disk space, the last data block of a small file may be + * allocated as only as many fragments of a large block as are + * necessary. The file system format retains only a single pointer + * to such a fragment, which is a piece of a single large block that + * has been divided. The size of such a fragment is determinable from + * information in the inode, using the ``blksize(fs, ip, lbn)'' macro. + * + * The file system records space availability at the fragment level; + * to determine block availability, aligned fragments are examined. + * + * The root inode is the root of the file system. + * Inode 0 can't be used for normal purposes and + * historically bad blocks were linked to inode 1, + * thus the root inode is 2. (inode 1 is no longer used for + * this purpose, however numerous dump tapes make this + * assumption, so we are stuck with it) + */ +#define ROOTINO ((ino_t)2) /* i number of all roots */ + +/* + * MINBSIZE is the smallest allowable block size. + * In order to insure that it is possible to create files of size + * 2^32 with only two levels of indirection, MINBSIZE is set to 4096. + * MINBSIZE must be big enough to hold a cylinder group block, + * thus changes to (struct cg) must keep its size within MINBSIZE. + * Note that super blocks are always of size SBSIZE, + * and that both SBSIZE and MAXBSIZE must be >= MINBSIZE. + */ +#define MINBSIZE 4096 + +/* + * The path name on which the file system is mounted is maintained + * in fs_fsmnt. MAXMNTLEN defines the amount of space allocated in + * the super block for this name. + * The limit on the amount of summary information per file system + * is defined by MAXCSBUFS. It is currently parameterized for a + * maximum of two million cylinders. + */ +#define MAXMNTLEN 512 +#define MAXCSBUFS 32 + +/* + * Per cylinder group information; summarized in blocks allocated + * from first cylinder group data blocks. These blocks have to be + * read in from fs_csaddr (size fs_cssize) in addition to the + * super block. + * + * N.B. sizeof(struct csum) must be a power of two in order for + * the ``fs_cs'' macro to work (see below). + */ +struct csum { + int cs_ndir; /* number of directories */ + int cs_nbfree; /* number of free blocks */ + int cs_nifree; /* number of free inodes */ + int cs_nffree; /* number of free frags */ +}; + +/* + * Super block for a file system. + */ +#define FS_MAGIC 0x011954 +struct fs +{ + int xxx1; /* struct fs *fs_link;*/ + int xxx2; /* struct fs *fs_rlink;*/ + daddr_t fs_sblkno; /* addr of super-block in filesys */ + daddr_t fs_cblkno; /* offset of cyl-block in filesys */ + daddr_t fs_iblkno; /* offset of inode-blocks in filesys */ + daddr_t fs_dblkno; /* offset of first data after cg */ + int fs_cgoffset; /* cylinder group offset in cylinder */ + int fs_cgmask; /* used to calc mod fs_ntrak */ + time_t fs_time; /* last time written */ + int fs_size; /* number of blocks in fs */ + int fs_dsize; /* number of data blocks in fs */ + int fs_ncg; /* number of cylinder groups */ + int fs_bsize; /* size of basic blocks in fs */ + int fs_fsize; /* size of frag blocks in fs */ + int fs_frag; /* number of frags in a block in fs */ +/* these are configuration parameters */ + int fs_minfree; /* minimum percentage of free blocks */ + int fs_rotdelay; /* num of ms for optimal next block */ + int fs_rps; /* disk revolutions per second */ +/* these fields can be computed from the others */ + int fs_bmask; /* ``blkoff'' calc of blk offsets */ + int fs_fmask; /* ``fragoff'' calc of frag offsets */ + int fs_bshift; /* ``lblkno'' calc of logical blkno */ + int fs_fshift; /* ``numfrags'' calc number of frags */ +/* these are configuration parameters */ + int fs_maxcontig; /* max number of contiguous blks */ + int fs_maxbpg; /* max number of blks per cyl group */ +/* these fields can be computed from the others */ + int fs_fragshift; /* block to frag shift */ + int fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */ + int fs_sbsize; /* actual size of super block */ + int fs_csmask; /* csum block offset */ + int fs_csshift; /* csum block number */ + int fs_nindir; /* value of NINDIR */ + int fs_inopb; /* value of INOPB */ + int fs_nspf; /* value of NSPF */ +/* yet another configuration parameter */ + int fs_optim; /* optimization preference, see below */ +/* these fields are derived from the hardware */ + int fs_npsect; /* # sectors/track including spares */ + int fs_interleave; /* hardware sector interleave */ + int fs_trackskew; /* sector 0 skew, per track */ + int fs_headswitch; /* head switch time, usec */ + int fs_trkseek; /* track-to-track seek, usec */ +/* sizes determined by number of cylinder groups and their sizes */ + daddr_t fs_csaddr; /* blk addr of cyl grp summary area */ + int fs_cssize; /* size of cyl grp summary area */ + int fs_cgsize; /* cylinder group size */ +/* these fields are derived from the hardware */ + int fs_ntrak; /* tracks per cylinder */ + int fs_nsect; /* sectors per track */ + int fs_spc; /* sectors per cylinder */ +/* this comes from the disk driver partitioning */ + int fs_ncyl; /* cylinders in file system */ +/* these fields can be computed from the others */ + int fs_cpg; /* cylinders per group */ + int fs_ipg; /* inodes per group */ + int fs_fpg; /* blocks per group * fs_frag */ +/* this data must be re-computed after crashes */ + struct csum fs_cstotal; /* cylinder summary information */ +/* these fields are cleared at mount time */ + char fs_fmod; /* super block modified flag */ + char fs_clean; /* file system is clean flag */ + char fs_ronly; /* mounted read-only flag */ + char fs_flags; /* currently unused flag */ + char fs_fsmnt[MAXMNTLEN]; /* name mounted on */ +/* these fields retain the current block allocation info */ + int fs_cgrotor; /* last cg searched */ +#if 1 + int was_fs_csp[MAXCSBUFS]; +#else + struct csum *fs_csp[MAXCSBUFS];/* list of fs_cs info buffers */ +#endif + int fs_cpc; /* cyl per cycle in postbl */ + short fs_opostbl[16][8]; /* old rotation block list head */ + long fs_sparecon[50]; /* reserved for future constants */ + long fs_contigsumsize; /* size of cluster summary array */ + long fs_maxsymlinklen; /* max length of an internal symlink */ + long fs_inodefmt; /* format of on-disk inodes */ + quad fs_maxfilesize; /* maximum representable file size */ + quad fs_qbmask; /* ~fs_bmask - for use with quad size */ + quad fs_qfmask; /* ~fs_fmask - for use with quad size */ + long fs_state; /* validate fs_clean field */ + int fs_postblformat; /* format of positional layout tables */ + int fs_nrpos; /* number of rotaional positions */ + int fs_postbloff; /* (short) rotation block list head */ + int fs_rotbloff; /* (u_char) blocks for each rotation */ + int fs_magic; /* magic number */ + u_char fs_space[1]; /* list of blocks for each rotation */ +/* actually longer */ +}; +/* + * Preference for optimization. + */ +#define FS_OPTTIME 0 /* minimize allocation time */ +#define FS_OPTSPACE 1 /* minimize disk fragmentation */ + +/* + * Rotational layout table format types + */ +#define FS_42POSTBLFMT -1 /* 4.2BSD rotational table format */ +#define FS_DYNAMICPOSTBLFMT 1 /* dynamic rotational table format */ +/* + * Macros for access to superblock array structures + */ +#define fs_postbl(fs, cylno) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_opostbl[cylno]) \ + : ((short *)((char *)(fs) + (fs)->fs_postbloff) + (cylno) * (fs)->fs_nrpos)) +#define fs_rotbl(fs) \ + (((fs)->fs_postblformat == FS_42POSTBLFMT) \ + ? ((fs)->fs_space) \ + : ((u_char *)((char *)(fs) + (fs)->fs_rotbloff))) + +/* + * Convert cylinder group to base address of its global summary info. + * + * N.B. This macro assumes that sizeof(struct csum) is a power of two. + */ +#define fs_cs(fs, indx) \ + fs_csp[(indx) >> (fs)->fs_csshift][(indx) & ~(fs)->fs_csmask] + +/* + * Cylinder group block for a file system. + */ +#define CG_MAGIC 0x090255 +struct cg { + int xxx1; /* struct cg *cg_link;*/ + int cg_magic; /* magic number */ + time_t cg_time; /* time last written */ + int cg_cgx; /* we are the cgx'th cylinder group */ + short cg_ncyl; /* number of cyl's this cg */ + short cg_niblk; /* number of inode blocks this cg */ + int cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int cg_rotor; /* position of last used block */ + int cg_frotor; /* position of last used frag */ + int cg_irotor; /* position of last used inode */ + int cg_frsum[MAXFRAG]; /* counts of available frags */ + int cg_btotoff; /* (long) block totals per cylinder */ + int cg_boff; /* (short) free block positions */ + int cg_iusedoff; /* (char) used inode map */ + int cg_freeoff; /* (u_char) free block map */ + int cg_nextfreeoff; /* (u_char) next available space */ + int cg_sparecon[16]; /* reserved for future use */ + u_char cg_space[1]; /* space for cylinder group maps */ +/* actually longer */ +}; +/* + * Macros for access to cylinder group array structures + */ +#define cg_blktot(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_btot) \ + : ((int *)((char *)(cgp) + (cgp)->cg_btotoff))) +#define cg_blks(fs, cgp, cylno) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_b[cylno]) \ + : ((short *)((char *)(cgp) + (cgp)->cg_boff) + (cylno) * (fs)->fs_nrpos)) +#define cg_inosused(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_iused) \ + : ((char *)((char *)(cgp) + (cgp)->cg_iusedoff))) +#define cg_blksfree(cgp) \ + (((cgp)->cg_magic != CG_MAGIC) \ + ? (((struct ocg *)(cgp))->cg_free) \ + : ((u_char *)((char *)(cgp) + (cgp)->cg_freeoff))) +#define cg_chkmagic(cgp) \ + ((cgp)->cg_magic == CG_MAGIC || ((struct ocg *)(cgp))->cg_magic == CG_MAGIC) + +/* + * The following structure is defined + * for compatibility with old file systems. + */ +struct ocg { + int xxx1; /* struct ocg *cg_link;*/ + int xxx2; /* struct ocg *cg_rlink;*/ + time_t cg_time; /* time last written */ + int cg_cgx; /* we are the cgx'th cylinder group */ + short cg_ncyl; /* number of cyl's this cg */ + short cg_niblk; /* number of inode blocks this cg */ + int cg_ndblk; /* number of data blocks this cg */ + struct csum cg_cs; /* cylinder summary information */ + int cg_rotor; /* position of last used block */ + int cg_frotor; /* position of last used frag */ + int cg_irotor; /* position of last used inode */ + int cg_frsum[8]; /* counts of available frags */ + int cg_btot[32]; /* block totals per cylinder */ + short cg_b[32][8]; /* positions of free blocks */ + char cg_iused[256]; /* used inode map */ + int cg_magic; /* magic number */ + u_char cg_free[1]; /* free block map */ +/* actually longer */ +}; + +/* + * Turn file system block numbers into disk block addresses. + * This maps file system blocks to device size blocks. + */ +#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb) +#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb) + +/* + * Cylinder group macros to locate things in cylinder groups. + * They calc file system addresses of cylinder group data structures. + */ +#define cgbase(fs, c) ((daddr_t)((fs)->fs_fpg * (c))) +#define cgstart(fs, c) \ + (cgbase(fs, c) + (fs)->fs_cgoffset * ((c) & ~((fs)->fs_cgmask))) +#define cgsblock(fs, c) (cgstart(fs, c) + (fs)->fs_sblkno) /* super blk */ +#define cgtod(fs, c) (cgstart(fs, c) + (fs)->fs_cblkno) /* cg block */ +#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */ +#define cgdmin(fs, c) (cgstart(fs, c) + (fs)->fs_dblkno) /* 1st data */ + +/* + * Macros for handling inode numbers: + * inode number to file system block offset. + * inode number to cylinder group number. + * inode number to file system block address. + */ +#define itoo(fs, x) ((x) % INOPB(fs)) +#define itog(fs, x) ((x) / (fs)->fs_ipg) +#define itod(fs, x) \ + ((daddr_t)(cgimin(fs, itog(fs, x)) + \ + (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs)))))) + +/* + * Give cylinder group number for a file system block. + * Give cylinder group block number for a file system block. + */ +#define dtog(fs, d) ((d) / (fs)->fs_fpg) +#define dtogd(fs, d) ((d) % (fs)->fs_fpg) + +/* + * Extract the bits for a block from a map. + * Compute the cylinder and rotational position of a cyl block addr. + */ +#define blkmap(fs, map, loc) \ + (((map)[(loc) / NBBY] >> ((loc) % NBBY)) & (0xff >> (NBBY - (fs)->fs_frag))) +#define cbtocylno(fs, bno) \ + ((bno) * NSPF(fs) / (fs)->fs_spc) +#define cbtorpos(fs, bno) \ + (((bno) * NSPF(fs) % (fs)->fs_spc / (fs)->fs_nsect * (fs)->fs_trackskew + \ + (bno) * NSPF(fs) % (fs)->fs_spc % (fs)->fs_nsect * (fs)->fs_interleave) % \ + (fs)->fs_nsect * (fs)->fs_nrpos / (fs)->fs_npsect) + +/* + * The following macros optimize certain frequently calculated + * quantities by using shifts and masks in place of divisions + * modulos and multiplications. + */ +#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \ + ((loc) & ~(fs)->fs_bmask) +#define fragoff(fs, loc) /* calculates (loc % fs->fs_fsize) */ \ + ((loc) & ~(fs)->fs_fmask) +#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \ + ((loc) >> (fs)->fs_bshift) +#define numfrags(fs, loc) /* calculates (loc / fs->fs_fsize) */ \ + ((loc) >> (fs)->fs_fshift) +#define blkroundup(fs, size) /* calculates roundup(size, fs->fs_bsize) */ \ + (((size) + (fs)->fs_bsize - 1) & (fs)->fs_bmask) +#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \ + (((size) + (fs)->fs_fsize - 1) & (fs)->fs_fmask) +#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \ + ((frags) >> (fs)->fs_fragshift) +#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \ + ((blks) << (fs)->fs_fragshift) +#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \ + ((fsb) & ((fs)->fs_frag - 1)) +#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \ + ((fsb) &~ ((fs)->fs_frag - 1)) + +/* + * Determine the number of available frags given a + * percentage to hold in reserve + */ +#define freespace(fs, percentreserved) \ + (blkstofrags((fs), (fs)->fs_cstotal.cs_nbfree) + \ + (fs)->fs_cstotal.cs_nffree - ((fs)->fs_dsize * (percentreserved) / 100)) + +/* + * Determining the size of a file block in the file system. + */ +#define blksize(fs, ip, lbn) \ + (((lbn) >= NDADDR || (ip)->i_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (ip)->i_size)))) +#define dblksize(fs, dip, lbn) \ + (((lbn) >= NDADDR || (dip)->di_size >= ((lbn) + 1) << (fs)->fs_bshift) \ + ? (fs)->fs_bsize \ + : (fragroundup(fs, blkoff(fs, (dip)->di_size)))) + +/* + * Number of disk sectors per block; assumes DEV_BSIZE byte sector size. + */ +#define NSPB(fs) ((fs)->fs_nspf << (fs)->fs_fragshift) +#define NSPF(fs) ((fs)->fs_nspf) + +/* + * INOPB is the number of inodes in a secondary storage block. + */ +#define INOPB(fs) ((fs)->fs_inopb) +#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift) + +/* + * NINDIR is the number of indirects in a file system block. + */ +#define NINDIR(fs) ((fs)->fs_nindir) + diff --git a/shared_src/fsys_ext2fs.c b/shared_src/fsys_ext2fs.c new file mode 100644 index 000000000..a800bdb57 --- /dev/null +++ b/shared_src/fsys_ext2fs.c @@ -0,0 +1,634 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "shared.h" + +#ifdef E2DEBUG +#include "pc_slice.h" +#else +#include "filesys.h" +#endif + +static int mapblock1, mapblock2; + +/* sizes are always in bytes, BLOCK values are always in DEV_BSIZE (sectors) */ +#define DEV_BSIZE 512 + +/* include/linux/fs.h */ +#define BLOCK_SIZE 1024 /* initial block size for superblock read */ +/* made up, defaults to 1 but can be passed via mount_opts */ +#define WHICH_SUPER 1 +/* kind of from fs/ext2/super.c */ +#define SBLOCK (WHICH_SUPER * BLOCK_SIZE / DEV_BSIZE) /* = 2 */ + +/* include/asm-i386/types.h */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; + +/* + * Constants relative to the data blocks, from ext2_fs.h + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* include/linux/ext2_fs.h */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __s32 s_log_frag_size; /* Fragment size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_frags_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_pad; + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + __u32 s_reserved[235]; /* Padding to the end of the block */ +}; + +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_pad; + __u32 bg_reserved[3]; +}; + +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Owner Uid */ + __u32 i_size; /* 4: Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* 12: Creation time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* 20: Deletion Time */ + __u16 i_gid; /* Group Id */ + __u16 i_links_count; /* 24: Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* 32: File flags */ + union { + struct { + __u32 l_i_reserved1; + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + struct { + __u32 m_i_reserved1; + } masix1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */ + __u32 i_version; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_dir_acl; /* Directory ACL */ + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u8 l_i_frag; /* Fragment number */ + __u8 l_i_fsize; /* Fragment size */ + __u16 i_pad1; + __u32 l_i_reserved2[2]; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + struct { + __u8 m_i_frag; /* Fragment number */ + __u8 m_i_fsize; /* Fragment size */ + __u16 m_pad1; + __u32 m_i_reserved2[2]; + } masix2; + } osd2; /* OS dependent 2 */ +}; + +/* linux/limits.h */ +#define NAME_MAX 255 /* # chars in a file name */ + +/* linux/posix_type.h */ +typedef long off_t; + +/* linux/ext2fs.h */ +#define EXT2_NAME_LEN 255 +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* linux/ext2fs.h */ +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + + +/* ext2/super.c */ +#define log2(n) ffz(~(n)) + +#define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ +#define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ + +/* made up, these are pointers into FSYS_BUF */ +/* read once, always stays there: */ +#define SUPERBLOCK \ + ((struct ext2_super_block *)(FSYS_BUF)) +#define GROUP_DESC \ + ((struct ext2_group_desc *) \ + ((int)SUPERBLOCK + sizeof(struct ext2_super_block))) +#define INODE \ + ((struct ext2_inode *)((int)GROUP_DESC + EXT2_BLOCK_SIZE(SUPERBLOCK))) +#define DATABLOCK1 \ + ((int)((int)INODE + sizeof(struct ext2_inode))) +#define DATABLOCK2 \ + ((int)((int)DATABLOCK1 + EXT2_BLOCK_SIZE(SUPERBLOCK))) + +/* linux/ext2_fs.h */ +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) +#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) + +/* linux/ext2_fs.h */ +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +/* kind of from ext2/super.c */ +#define EXT2_BLOCK_SIZE(s) (1 << EXT2_BLOCK_SIZE_BITS(s)) +/* linux/ext2fs.h */ +#define EXT2_DESC_PER_BLOCK(s) \ + (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +/* linux/stat.h */ +#define S_IFMT 00170000 +#define S_IFREG 0100000 +#define S_IFDIR 0040000 +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) + +/* include/asm-i386/bitops.h */ +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +__inline__ unsigned long ffz(unsigned long word) +{ + __asm__("bsfl %1,%0" + :"=r" (word) + :"r" (~word)); + return word; +} + +/* check filesystem types and read superblock into memory buffer */ +int +ext2fs_mount(void) +{ + int retval = 1; + + if ( (((current_drive & 0x80) || (current_slice != 0)) + && (current_slice != PC_SLICE_TYPE_EXT2FS) + && (current_slice != (PC_SLICE_TYPE_BSD | (FS_OTHER<<8)))) + || part_length < (SBLOCK + (sizeof(struct ext2_super_block)/DEV_BSIZE)) + || !devread(SBLOCK, 0, sizeof(struct ext2_super_block), (int)SUPERBLOCK) + || SUPERBLOCK->s_magic != EXT2_SUPER_MAGIC) + retval = 0; + + return retval; +} + +/* not part of the interface + takes a file system block number and reads it into area pointed + to by buffer */ +int +ext2_rdfsb (int fsblock, int buffer) { +#ifdef E2DEBUG + printf("fsblock %d buffer %d\n", fsblock, buffer); +#endif /* E2DEBUG */ + return devread(fsblock * EXT2_BLOCK_SIZE(SUPERBLOCK) / DEV_BSIZE, 0, + EXT2_BLOCK_SIZE(SUPERBLOCK), (int)buffer); +} + +/* from + ext2/inode.c:ext2_bmap() +*/ +/* not part of interface + maps "logical block" (the file offset div blocksize) into + "physical blocks" (the location in the file system) via an inode */ +int +ext2fs_block_map(int logical_block) +{ + +#ifdef E2DEBUG + unsigned char * i; + for (i = (unsigned char *)INODE; + i < ((unsigned char *)INODE + sizeof(struct ext2_inode)); + i++) { + printf("%c", "0123456789abcdef"[*i >> 4]); + printf("%c", "0123456789abcdef"[*i % 16]); + if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); } + else { printf(" "); } + } + printf("logical block %d\n", logical_block); +#endif /* E2DEBUG */ + + /* if it is directly pointed to by the inode, return that physical addr */ + if (logical_block < EXT2_NDIR_BLOCKS) { +#ifdef E2DEBUG + printf ("returning %d\n", (unsigned char *)(INODE->i_block[logical_block])); + printf ("returning %d\n", INODE->i_block[logical_block]); +#endif /* E2DEBUG */ + return INODE->i_block[logical_block]; + } + /* else */ + logical_block -= EXT2_NDIR_BLOCKS; + /* try the indirect block */ + if (logical_block < EXT2_ADDR_PER_BLOCK(SUPERBLOCK)) { + if ( mapblock1 != 1 + && !ext2_rdfsb(INODE->i_block[EXT2_IND_BLOCK], DATABLOCK1)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 1; + return ((__u32 *)DATABLOCK1)[logical_block]; + } + /* else */ + logical_block -= EXT2_ADDR_PER_BLOCK(SUPERBLOCK); + /* now try the double indirect block */ + if (logical_block < (1 << (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK) * 2))) { + int bnum; + if ( mapblock1 != 2 + && !ext2_rdfsb(INODE->i_block[EXT2_DIND_BLOCK], DATABLOCK1)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 2; + if ( (bnum = (((__u32 *)DATABLOCK1) + [logical_block >> EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK)])) + != mapblock2 + && !ext2_rdfsb(bnum, DATABLOCK2)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock2 = bnum; + return ((__u32 *)DATABLOCK2) + [logical_block & (EXT2_ADDR_PER_BLOCK(SUPERBLOCK) - 1)]; + } + /* else */ + mapblock2 = -1; + logical_block -= (1 << (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK) * 2)); + if ( mapblock1 != 3 + && !ext2_rdfsb(INODE->i_block[EXT2_TIND_BLOCK], DATABLOCK1)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + mapblock1 = 3; + if (!ext2_rdfsb(((__u32 *)DATABLOCK1) + [logical_block >> (EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK)*2)], + DATABLOCK2)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + if (!ext2_rdfsb(((__u32 *)DATABLOCK2) + [(logical_block >> EXT2_ADDR_PER_BLOCK_BITS(SUPERBLOCK)) + & (EXT2_ADDR_PER_BLOCK(SUPERBLOCK) - 1)], + DATABLOCK2)) { + errnum = ERR_FSYS_CORRUPT; + return -1; + } + return ((__u32 *)DATABLOCK2) + [logical_block & (EXT2_ADDR_PER_BLOCK(SUPERBLOCK)-1)]; +} + +/* preconditions: all preconds of ext2fs_block_map */ +int +ext2fs_read(int addr, int len) +{ + int logical_block; + int offset; + int map; + int ret = 0; + int size = 0; + +#ifdef E2DEBUG + unsigned char * i; + for (i = (unsigned char *)INODE; + i < ((unsigned char *)INODE + sizeof(struct ext2_inode)); + i++) { + printf("%c", "0123456789abcdef"[*i >> 4]); + printf("%c", "0123456789abcdef"[*i % 16]); + if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); } + else { printf(" "); } + } +#endif /* E2DEBUG */ + while(len > 0) { + /* find the (logical) block component of our location */ + logical_block = filepos >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK); + offset = filepos & (EXT2_BLOCK_SIZE(SUPERBLOCK) - 1); + map = ext2fs_block_map(logical_block); +#ifdef E2DEBUG + printf("map=%d\n", map); +#endif /* E2DEBUG */ + if (map < 0) + break; + + size = EXT2_BLOCK_SIZE(SUPERBLOCK); + size -= offset; + if (size > len) + size = len; + +#ifndef NO_FANCY_STUFF + debug_fs_func = debug_fs; +#endif /* NO_FANCY_STUFF */ + + devread(map * EXT2_BLOCK_SIZE(SUPERBLOCK) / DEV_BSIZE, + offset, size, addr); + +#ifndef NO_FANCY_STUFF + debug_fs_func = NULL; +#endif /* NO_FANCY_STUFF */ + + addr += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + + +/* Based on: + def_blk_fops points to + blkdev_open, which calls (I think): + sys_open() + do_open() + open_namei() + dir_namei() which accesses current->fs->root + fs->root was set during original mount: + (something)... which calls (I think): + ext2_read_super() + iget() + __iget() + read_inode() + ext2_read_inode() + uses desc_per_block_bits, which is set in ext2_read_super() + also uses group descriptors loaded during ext2_read_super() + lookup() + ext2_lookup() + ext2_find_entry() + ext2_getblk() + +*/ + +/* preconditions: ext2fs_mount already executed, therefore supblk in buffer + * known as SUPERBLOCK + * returns: 0 if error, nonzero iff we were able to find the file successfully + * postconditions: on a nonzero return, buffer known as INODE contains the + * inode of the file we were trying to look up + * side effects: messes up GROUP_DESC buffer area + */ +int +ext2fs_dir(char *dirname) +{ + int current_ino = EXT2_ROOT_INO; /* start at the root */ + int group_id; /* which group the inode is in */ + int group_desc; /* fs pointer to that group */ + int desc; /* index within that group */ + int ino_blk; /* fs pointer of the inode's information */ + int str_chk; /* used to hold the results of a string compare */ + struct ext2_group_desc * gdp; + struct ext2_inode * raw_inode; /* inode info corresponding to current_ino */ + + char *rest; + char ch; /* temp char holder */ + + int off; /* offset within block of directory entry (off mod blocksize) */ + int loc; /* location within a directory */ + int blk; /* which data blk within dir entry (off div blocksize) */ + long map; /* fs pointer of a particular block from dir entry */ + struct ext2_dir_entry *dp; /* pointer to directory entry */ +#ifdef E2DEBUG + unsigned char *i; +#endif E2DEBUG + + /* loop invariants: + current_ino = inode to lookup + dirname = pointer to filename component we are cur looking up within + the directory known pointed to by current_ino (if any) + */ + + while (1) { +#ifdef E2DEBUG + printf("inode %d\n", current_ino); + printf("dirname=%s\n", dirname); +#endif /* E2DEBUG */ + + /* look up an inode */ + group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group); + group_desc = group_id >> log2(EXT2_DESC_PER_BLOCK(SUPERBLOCK)); + desc = group_id & (EXT2_DESC_PER_BLOCK(SUPERBLOCK) - 1); +#ifdef E2DEBUG + printf("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group, + EXT2_DESC_PER_BLOCK(SUPERBLOCK)); + printf("group_id=%d group_desc=%d desc=%d\n", group_id, group_desc, desc); +#endif /* E2DEBUG */ + if (!ext2_rdfsb((WHICH_SUPER + group_desc + 1), (int)GROUP_DESC)) { + return 0; + } + gdp = GROUP_DESC; + ino_blk = gdp[desc].bg_inode_table + + (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) + >> log2(EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode))); +#ifdef E2DEBUG + printf("inode table fsblock=%d\n", ino_blk); +#endif /* E2DEBUG */ + if (!ext2_rdfsb(ino_blk, (int)INODE)) { + return 0; + } + + /* reset indirect blocks! */ + mapblock2 = mapblock1 = -1; + + raw_inode = INODE + + ((current_ino - 1) + & (EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode) - 1)); +#ifdef E2DEBUG + printf("ipb=%d, sizeof(inode)=%d\n", + (EXT2_BLOCK_SIZE(SUPERBLOCK) / sizeof(struct ext2_inode)), + sizeof(struct ext2_inode)); + printf("inode=%x, raw_inode=%x\n", INODE, raw_inode); + printf("offset into inode table block=%d\n", (int)raw_inode - (int)INODE); + for (i = (unsigned char *)INODE; i <= (unsigned char *)raw_inode; i++) { + printf("%c", "0123456789abcdef"[*i >> 4]); + printf("%c", "0123456789abcdef"[*i % 16]); + if (!((i + 1 - (unsigned char *)INODE) % 16)) { printf("\n"); } + else { printf(" "); } + } + printf("first word=%x\n", *((int *)raw_inode)); +#endif /* E2DEBUG */ + + /* copy inode to fixed location */ + bcopy((void *)raw_inode, (void *)INODE, sizeof(struct ext2_inode)); + +#ifdef E2DEBUG + printf("first word=%x\n", *((int *)INODE)); +#endif /* E2DEBUG */ + + /* if end of filename, INODE points to the file's inode */ + if (!*dirname || isspace(*dirname)) + { + if (!S_ISREG(INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = (INODE->i_size); + return 1; + } + + /* else we have to traverse a directory */ + + /* skip over slashes */ + while (*dirname == '/') + dirname++; + + /* if this isn't a directory of sufficient size to hold our file, abort */ + if (!(INODE->i_size) || !S_ISDIR(INODE->i_mode)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + /* skip to next slash or end of filename (space) */ + for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ; + + /* look through this directory and find the next filename component */ + /* invariant: rest points to slash after the next filename component */ + *rest = 0; + loc = 0; + + do { + +#ifdef E2DEBUG + printf("dirname=%s, rest=%s, loc=%d\n", dirname, rest, loc); +#endif /* E2DEBUG */ + + /* if our location/byte offset into the directory exceeds the size, + give up */ + if (loc >= INODE->i_size) { + if (print_possibilities < 0) { + putchar('\n'); + } + else { + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + return (print_possibilities < 0); + } + + /* else, find the (logical) block component of our location */ + blk = loc >> EXT2_BLOCK_SIZE_BITS(SUPERBLOCK); + + /* now we know which logical block of the directory entry we are looking + for, now we have to translate that to the physical (fs) block on + the disk */ + map = ext2fs_block_map(blk); +#ifdef E2DEBUG + printf("fs block=%d\n", map); +#endif /* E2DEBUG */ + mapblock2 = -1; + if ((map < 0) || !ext2_rdfsb(map, DATABLOCK2)) { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + off = loc & (EXT2_BLOCK_SIZE(SUPERBLOCK) - 1); + dp = (struct ext2_dir_entry *)(DATABLOCK2 + off); + /* advance loc prematurely to next on-disk directory entry */ + loc += dp->rec_len; + + /* NOTE: ext2fs filenames are NOT null-terminated */ + +#ifdef E2DEBUG + printf("directory entry ino=%d\n", dp->inode); + if (dp->inode) + printf("entry=%s\n", dp->name); +#endif /* E2DEBUG */ + + if (dp->inode) + { + int saved_c = dp->name[dp->name_len]; + + dp->name[dp->name_len] = 0; + str_chk = strcmp(dirname, dp->name); + + if (print_possibilities && ch != '/' + && (!*dirname || str_chk <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + printf(" %s", dp->name); + } + + dp->name[dp->name_len] = saved_c; + } + + } while (!dp->inode || (str_chk || (print_possibilities && ch != '/')) ); + + current_ino = dp->inode; + *(dirname = rest) = ch; + } + /* never get here */ +} diff --git a/shared_src/fsys_fat.c b/shared_src/fsys_fat.c new file mode 100644 index 000000000..e91d0d0f5 --- /dev/null +++ b/shared_src/fsys_fat.c @@ -0,0 +1,256 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + + +#include "shared.h" + +#include "filesys.h" + +#include "fat.h" + +static int num_clust; +static int mapblock; +static int data_offset; +static int fat_size; + +/* pointer(s) into filesystem info buffer for DOS stuff */ +#define BPB ( FSYS_BUF + 32256 ) /* 512 bytes long */ +#define FAT_BUF ( FSYS_BUF + 30208 ) /* 4 sector FAT buffer */ + +int +fat_mount(void) +{ + int retval = 1; + + if ( (((current_drive & 0x80) || (current_slice != 0)) + && (current_slice != PC_SLICE_TYPE_FAT12) + && (current_slice != PC_SLICE_TYPE_FAT16_LT32M) + && (current_slice != PC_SLICE_TYPE_FAT16_GT32M) + && (current_slice != (PC_SLICE_TYPE_BSD | (FS_MSDOS<<8)))) + || !devread(0, 0, SECTOR_SIZE, BPB) + || FAT_BPB_BYTES_PER_SECTOR(BPB) != SECTOR_SIZE + || FAT_BPB_SECT_PER_CLUST(BPB) < 1 || FAT_BPB_SECT_PER_CLUST(BPB) > 64 + || (FAT_BPB_SECT_PER_CLUST(BPB) & (FAT_BPB_SECT_PER_CLUST(BPB) - 1)) + || !( (current_drive & 0x80) + || FAT_BPB_FLOPPY_NUM_SECTORS(BPB) ) ) + retval = 0; + else + { + mapblock = -4096; + data_offset = FAT_BPB_DATA_OFFSET(BPB); + num_clust = FAT_BPB_NUM_CLUST(BPB) + 2; + if (num_clust > FAT_MAX_12BIT_CLUST) + fat_size = 4; + else + fat_size = 3; + } + + return retval; +} + + +static int +fat_create_blocklist(int first_fat_entry) +{ + BLK_CUR_FILEPOS = 0; + BLK_CUR_BLKNUM = 0; + BLK_CUR_BLKLIST = BLK_BLKLIST_START; + block_file = 1; + filepos = 0; + + if (first_fat_entry < 0) + { + /* root directory */ + + BLK_BLKSTART(BLK_BLKLIST_START) = FAT_BPB_ROOT_DIR_START(BPB); + fsmax = filemax = SECTOR_SIZE * (BLK_BLKLENGTH(BLK_BLKLIST_START) + = FAT_BPB_ROOT_DIR_LENGTH(BPB)); + } + else /* any real directory/file */ + { + int blk_cur_blklist = BLK_BLKLIST_START, blk_cur_blknum; + int last_fat_entry, new_mapblock; + + fsmax = 0; + + do + { + BLK_BLKSTART(blk_cur_blklist) + = (first_fat_entry-2) * FAT_BPB_SECT_PER_CLUST(BPB) + data_offset; + blk_cur_blknum = 0; + + do + { + blk_cur_blknum += FAT_BPB_SECT_PER_CLUST(BPB); + last_fat_entry = first_fat_entry; + + /* + * Do FAT table translation here! + */ + + new_mapblock = (last_fat_entry * fat_size) >> 1; + if (new_mapblock > (mapblock + 2045) + || new_mapblock < (mapblock + 3)) + { + mapblock = ( (new_mapblock < 6) ? 0 : + ((new_mapblock - 6) & ~0x1FF) ); + if (!devread((mapblock>>9)+FAT_BPB_FAT_START(BPB), + 0, SECTOR_SIZE * 4, FAT_BUF)) + return 0; + } + + first_fat_entry + = *((unsigned short *) (FAT_BUF + (new_mapblock - mapblock))); + + if (num_clust <= FAT_MAX_12BIT_CLUST) + { + if (last_fat_entry & 1) + first_fat_entry >>= 4; + else + first_fat_entry &= 0xFFF; + } + + if (first_fat_entry < 2) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + } + while (first_fat_entry == (last_fat_entry + 1) + && first_fat_entry < num_clust); + + BLK_BLKLENGTH(blk_cur_blklist) = blk_cur_blknum; + fsmax += blk_cur_blknum * SECTOR_SIZE; + blk_cur_blklist += BLK_BLKLIST_INC_VAL; + } + while (first_fat_entry < num_clust && blk_cur_blklist < (FAT_BUF - 7)); + } + + return 1; +} + + +/* XX FAT filesystem uses the block-list filesystem read function, + so none is defined here. */ + + +int +fat_dir(char *dirname) +{ + char *rest, ch, filename[13], dir_buf[FAT_DIRENTRY_LENGTH]; + int attrib = FAT_ATTRIB_DIR, map = -1; + +/* main loop to find desired directory entry */ +loop: + + if (!fat_create_blocklist(map)) + return 0; + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (!*dirname || isspace(*dirname)) + { + if (attrib & FAT_ATTRIB_DIR) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + return 1; + } + + /* continue with the file/directory name interpretation */ + + while (*dirname == '/') + dirname++; + + filemax = fsmax; + + if (!filemax || !(attrib & FAT_ATTRIB_DIR)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ; + + *rest = 0; + + do + { + if (read((int)dir_buf, FAT_DIRENTRY_LENGTH) != FAT_DIRENTRY_LENGTH) + { + if (!errnum) + { + if (print_possibilities < 0) + { + putchar('\n'); + return 1; + } + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + } + + return 0; + } + + if (!FAT_DIRENTRY_VALID(dir_buf)) + continue; + + /* XXX convert to 8.3 filename format here */ + { + int i, j, c; + + for (i = 0; i < 8 && (c = filename[i] = tolower(dir_buf[i])) + && !isspace(c) ; i++) ; + + filename[i++] = '.'; + + for (j = 0; j < 3 && (c = filename[i+j] = tolower(dir_buf[8+j])) + && !isspace(c) ; j++) ; + + if (j == 0) + i--; + + filename[i+j] = 0; + } + + if (print_possibilities && ch != '/' + && (!*dirname || strcmp(dirname, filename) <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + printf(" %s", filename); + } + } + while (strcmp(dirname, filename) != 0 || (print_possibilities && ch != '/')); + + *(dirname = rest) = ch; + + attrib = FAT_DIRENTRY_ATTRIB(dir_buf); + filemax = FAT_DIRENTRY_FILELENGTH(dir_buf); + map = FAT_DIRENTRY_FIRST_CLUSTER(dir_buf); + + /* go back to main loop at top of function */ + goto loop; +} + + diff --git a/shared_src/fsys_ffs.c b/shared_src/fsys_ffs.c new file mode 100644 index 000000000..1a1ddc07d --- /dev/null +++ b/shared_src/fsys_ffs.c @@ -0,0 +1,267 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Elements of this file were originally from the FreeBSD "biosboot" + * bootloader file "disk.c" dated 4/12/95. + * + * The license and header comments from that file are included here. + */ + +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd + * $Id$ + */ + + + +#include "shared.h" + +#include "filesys.h" + +#include "defs.h" +#include "disk_inode.h" +#include "disk_inode_ffs.h" +#include "dir.h" +#include "fs.h" + +/* used for filesystem map blocks */ +static int mapblock; + +/* pointer to superblock */ +#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 )) +#define INODE ((struct icommon *) ( FSYS_BUF + 16384 )) +#define MAPBUF ( FSYS_BUF + 24576 ) + + +int +ffs_mount(void) +{ + int retval = 1; + + if ( (((current_drive & 0x80) || (current_slice != 0)) + && current_slice != (PC_SLICE_TYPE_BSD | (FS_BSDFFS<<8))) + || part_length < (SBLOCK + (SBSIZE/DEV_BSIZE)) + || !devread(SBLOCK, 0, SBSIZE, (int) SUPERBLOCK) + || SUPERBLOCK->fs_magic != FS_MAGIC ) + retval = 0; + + mapblock = -1; + + return retval; +} + +int +block_map(int file_block) +{ + int bnum; + + if (file_block < NDADDR) + return(INODE->i_db[file_block]); + + if ( (bnum = fsbtodb(SUPERBLOCK, INODE->i_ib[0])) != mapblock ) + { + if (!devread(bnum, 0, SUPERBLOCK->fs_bsize, MAPBUF)) + { + mapblock = -1; + errnum = ERR_FSYS_CORRUPT; + return -1; + } + + mapblock = bnum; + } + + return (((int *)MAPBUF)[(file_block - NDADDR) % NINDIR(SUPERBLOCK)]); +} + + +int +ffs_read(int addr, int len) +{ + int logno, off, size, map, ret = 0; + + while (len && !errnum) + { + off = blkoff(SUPERBLOCK, filepos); + logno = lblkno(SUPERBLOCK, filepos); + size = blksize(SUPERBLOCK, INODE, logno); + + if ((map = block_map(logno)) < 0) + break; + + size -= off; + + if (size > len) + size = len; + +#ifndef NO_FANCY_STUFF + debug_fs_func = debug_fs; +#endif /* NO_FANCY_STUFF */ + + devread(fsbtodb(SUPERBLOCK, map), off, size, addr); + +#ifndef NO_FANCY_STUFF + debug_fs_func = NULL; +#endif /* NO_FANCY_STUFF */ + + addr += size; + len -= size; + filepos += size; + ret += size; + } + + if (errnum) + ret = 0; + + return ret; +} + + +int +ffs_dir(char *dirname) +{ + char *rest, ch; + int block, off, loc, map, ino = ROOTINO; + struct direct *dp; + +/* main loop to find destination inode */ +loop: + + /* load current inode (defaults to the root inode) */ + + if (!devread(fsbtodb(SUPERBLOCK,itod(SUPERBLOCK,ino)), + 0, SUPERBLOCK->fs_bsize, FSYS_BUF)) + return 0; /* XXX what return value? */ + + bcopy((void *)&(((struct dinode *)FSYS_BUF)[ino % (SUPERBLOCK->fs_inopb)]), + (void *)INODE, sizeof (struct dinode)); + + /* if we have a real file (and we're not just printing possibilities), + then this is where we want to exit */ + + if (!*dirname || isspace(*dirname)) + { + if ((INODE->i_mode & IFMT) != IFREG) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + filemax = INODE->i_size; + + /* incomplete implementation requires this! */ + fsmax = (NDADDR + NINDIR(SUPERBLOCK)) * SUPERBLOCK->fs_bsize; + return 1; + } + + /* continue with file/directory name interpretation */ + + while (*dirname == '/') + dirname++; + + if (!(INODE->i_size) || ((INODE->i_mode & IFMT) != IFDIR)) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + + for (rest = dirname; (ch = *rest) && !isspace(ch) && ch != '/'; rest++) ; + + *rest = 0; + loc = 0; + + /* loop for reading a the entries in a directory */ + + do + { + if (loc >= INODE->i_size) + { + putchar('\n'); + + if (print_possibilities < 0) + return 1; + + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; + } + + if (!(off = blkoff(SUPERBLOCK, loc))) + { + block = lblkno(SUPERBLOCK, loc); + + if ( (map = block_map(block)) < 0 + || !devread(fsbtodb(SUPERBLOCK, map), 0, + blksize(SUPERBLOCK, INODE, block), FSYS_BUF) ) + { + errnum = ERR_FSYS_CORRUPT; + *rest = ch; + return 0; + } + } + + dp = (struct direct *)(FSYS_BUF + off); + loc += dp->d_reclen; + + if (dp->d_ino && print_possibilities && ch != '/' + && (!*dirname || strcmp(dirname, dp->d_name) <= 0)) + { + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + + printf(" %s", dp->d_name); + } + } + while (!dp->d_ino || (strcmp(dirname, dp->d_name) != 0 + || (print_possibilities && ch != '/')) ); + + /* only get here if we have a matching directory entry */ + + ino = dp->d_ino; + *(dirname = rest) = ch; + + /* go back to main loop at top of function */ + goto loop; +} + + diff --git a/shared_src/gunzip.c b/shared_src/gunzip.c new file mode 100644 index 000000000..ddae1ffe1 --- /dev/null +++ b/shared_src/gunzip.c @@ -0,0 +1,659 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Most of this file was originally the source file "inflate.c", written + * by Mark Adler. It has been very heavily modified. In particular, the + * original would run through the whole file at once, and this version can + * be stopped and restarted on any boundary during the decompression process. + * + * The license and header comments that file are included here. + */ + +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* You can do whatever you like with this source file, though I would + prefer that if you modify it and redistribute it that you include + comments to that effect with your name and the date. Thank you. + [The history has been moved to the file ChangeLog.] + */ + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor deals with some chunk of data at a time, and + decides which method to use on a chunk-by-chunk basis. A chunk might + typically be 32K or 64K. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data is compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data is preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block codes up smaller that way (usually for quite small + chunks), otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block, and so + can code it much better than the pre-determined fixed codes. + + The Huffman codes themselves are decoded using a mutli-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarly, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +#include "shared.h" + +#include "filesys.h" + +/* so we can disable decompression */ +int no_decompression = 0; + +/* used to tell if "read" should be redirected to "gunzip_read" */ +int compressed_file; + +/* internal variables only */ +static int gzip_data_offset; +static int gzip_filepos; +static int gzip_filemax; +static int gzip_fsmax; +static int saved_filepos; +static unsigned long gzip_crc; + +/* internal extra variables for use of inflate code */ +static int block_type; +static int block_len; + + +/* Function prototypes */ +static void initialize_tables(void); +static int huft_build(unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *); +static int huft_free(struct huft *); +static int inflate_codes(struct huft *, struct huft *, int, int); + + +/* internal variable swap function */ +static void +gunzip_swap_values(void) +{ + register int itmp; + + /* swap filepos */ + itmp = filepos; + filepos = gzip_filepos; + gzip_filepos = itmp; + + /* swap filemax */ + itmp = filemax; + filemax = gzip_filemax; + gzip_filemax = itmp; + + /* swap fsmax */ + itmp = fsmax; + fsmax = gzip_fsmax; + gzip_fsmax = itmp; +} + + +/* internal function for eating variable-length header fields */ +static int +bad_field(int len) +{ + char ch = 1; + int not_retval = 1; + + do + { + if (len >= 0) + { + if (!(len--)) + break; + } + else + { + if (!ch) + break; + } + } + while ((not_retval = read((int)&ch, 1)) == 1); + + return (!not_retval); +} + + +/* Little-Endian defines for the 2-byte magic number for gzip files */ +#define GZIP_HDR_LE 0x8B1F +#define OLD_GZIP_HDR_LE 0x9E1F + +/* Compression methods (see algorithm.doc) */ +#define STORED 0 +#define COMPRESSED 1 +#define PACKED 2 +#define LZHED 3 +/* methods 4 to 7 reserved */ +#define DEFLATED 8 +#define MAX_METHODS 9 + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define UNSUPP_FLAGS (CONTINUATION|ENCRYPTED|RESERVED) + +/* inflate block codes */ +#define INFLATE_STORED 0 +#define INFLATE_FIXED 1 +#define INFLATE_DYNAMIC 2 + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* + * Window Size + * + * This must be a power of two, and at least 32K for zip's deflate method + */ + +#define WSIZE 0x8000 + + +int +gunzip_test_header(void) +{ + unsigned char buf[10]; + + /* "compressed_file" is already reset to zero by this point */ + + /* + * This checks if the file is gzipped. If a problem occurs here + * (other than a real error with the disk) then we don't think it + * is a compressed file, and simply mark it as such. + */ + if (no_decompression || read((int)buf, 10) != 10 + || ((*((unsigned short *) buf) != GZIP_HDR_LE) + & (*((unsigned short *) buf) != OLD_GZIP_HDR_LE))) + { + filepos = 0; + return (!errnum); + } + + /* + * This does consistency checking on the header data. If a + * problem occurs from here on, then we have corrupt or otherwise + * bad data, and the error should be reported to the user. + */ + if (buf[2] != DEFLATED || (buf[3] & UNSUPP_FLAGS) + || ((buf[3] & EXTRA_FIELD) + && (read((int)buf, 2) != 2 || bad_field(*((unsigned short *) buf)))) + || ((buf[3] & ORIG_NAME) && bad_field(-1)) + || ((buf[3] & COMMENT) && bad_field(-1)) + || ((gzip_data_offset = filepos), (filepos = filemax - 8), + (read((int)buf, 8) != 8))) + { + if (!errnum) + errnum = ERR_BAD_GZIP_HEADER; + + return 0; + } + + gzip_crc = *((unsigned long *) buf); + gzip_fsmax = gzip_filemax = *((unsigned long *) (buf+4)); + + initialize_tables(); + + compressed_file = 1; + gunzip_swap_values(); + /* + * Now "gzip_*" values refer to the compressed data. + */ + + filepos = 0; + + return 1; +} + + +uch slide[WSIZE]; + + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). + Valid extra bits are 0..13. e == 15 is EOB (end of block), e == 16 + means that v is a literal, 16 < e < 32 means that v is a pointer to + the next table, which codes e - 16 bits, and lastly e == 99 indicates + an unused code. If a code with e == 99 is looked up, this implies an + error in the data. */ +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ + +/* current position in slide */ +unsigned wp; +#define flush_output(w) (wp=(w),flush_window()) + + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +int lbits = 9; /* bits in base literal/length lookup table */ +int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +unsigned hufts; /* track memory usage */ + + + +/* XXXXXX */ + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed, and are initialized at the beginning of a + routine that uses these macros from a global bit buffer and count. + + If we assume that EOB will be the longest code, then we will never + ask for bits with NEEDBITS that are beyond the end of the stream. + So, NEEDBITS should not read any more bytes than are needed to + meet the request. Then no bytes need to be "returned" to the buffer + at the end of the last block. + + However, this assumption is not true for fixed blocks--the EOB code + is 7 bits, but the other literal/length codes can be 8 or 9 bits. + (The EOB code is shorter than other codes because fixed blocks are + generally short. So, while a block always has an EOB, many other + literal/length codes have a significantly lower probability of + showing up at all.) However, by making the first table have a + lookup of seven bits, the EOB code will be found in that first + lookup, and so will not require that too many bits be pulled from + the stream. + */ + +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ + +ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)get_byte())<>=(n);k-=(n);} + +static void +needbits(int n) +{ + register k = bk; + + while (k < n) + { + bb |= ((ulg) get_byte()) << k; + k += 8; + } + + bk = k; +} + +#define dumpbits(n) {bb>>=(n);bk-=(n);} + + +static void +init_stored_block(void) +{ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + + new_block = 0; + + /* go to byte boundary */ + DUMPBITS(k & 7); + + /* get the length and its complement */ + NEEDBITS(16); + block_len = ((unsigned)b & 0xffff); + DUMPBITS(16); + NEEDBITS(16); + if (block_len != (unsigned)((~b) & 0xffff)) + errnum = ERR_BAD_GZIP_DATA; + DUMPBITS(16); + + /* restore global variables */ + bb = b; + bk = k; +} + + +static void +get_new_block(void) +{ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + hufts = 0; + + /* make local bit buffer */ + b = bb; + k = bk; + + /* read in last block bit */ + NEEDBITS(1); + last_block = (int)b & 1; + DUMPBITS(1); + + /* read in block type */ + NEEDBITS(2); + block_type = (unsigned)b & 3; + DUMPBITS(2); + + /* restore the global bit buffer */ + bb = b; + bk = k; +} + + +static void +inflate_window(void) +{ + /* initialize window */ + wp = 0; + + /* + * Main decompression loop. + */ + + while (wp < WSIZE && !errnum) + { + if (!block_len) + get_new_block(); + + if (block_type > INFLATE_DYNAMIC) + { + errnum = ERR_BAD_GZIP_DATA; + continue; + } + + if (block_type == INFLATE_STORED) + { + /* + * This is basically a glorified pass-through + */ + + if (!block_len) + init_stored_block(); + + while (block_len && wp < WSIZE && !errnum) + { + slide[wp++] = get_byte(); + block_len--; + } + + continue; + } + + /* + * Init other kind of block. + */ + + if (!block_len) + { + if (block_type == INFLATE_FIXED) + init_fixed_block(); + if (block_type == INFLATE_DYNAMIC) + init_dynamic_block(); + } + + /* + * Expand other kind of block. + */ + + if (inflate_codes() && !block_len) + { + /* we're done with the block, so free data structures */ + huft_free(tl); + huft_free(td); + } + } + + saved_filepos += WSIZE; +} + + +static void +initialize_tables(void) +{ + saved_filepos = 0; + filepos = gzip_data_offset; + + /* initialize window, bit buffer */ + bk = 0; + bb = 0; + + /* reset partial decompression code */ + last_block = 0; +} + + +int +gunzip_read(int addr, int len) +{ + int last_block, size; /* last block flag */ + int ret = 0; + + compressed_file = 0; + gunzip_swap_values(); + /* + * Now "gzip_*" values refer to the uncompressed data. + */ + + /* do we reset decompression to the beginning of the file? */ + if (saved_filepos > gzip_filepos+WSIZE) + initialize_tables(); + + /* + * This loop operates upon uncompressed data only. The only + * special thing it does is to make sure the decompression + * window is within the range of data it needs. + */ + + while (len > 0 && !errnum) + { + register int size; + + while (gzip_filepos >= saved_filepos) + inflate_window(); + + size = saved_filepos - gzip_filepos; + if (size > len) + size = len; + + bcopy((char *)slide, (char *)addr, size); + + addr += size; + len -= size; + gzip_filepos += size; + ret += size; + } + + compressed_file = 1; + gunzip_swap_values(); + /* + * Now "gzip_*" values refer to the compressed data. + */ + + if (errnum) + ret = 0; + + return ret; +} + diff --git a/shared_src/i386-elf.h b/shared_src/i386-elf.h new file mode 100644 index 000000000..7d3800c00 --- /dev/null +++ b/shared_src/i386-elf.h @@ -0,0 +1,205 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* 32-bit data types */ + +typedef unsigned long Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned long Elf32_Off; +typedef signed long Elf32_Sword; +typedef unsigned long Elf32_Word; +/* "unsigned char" already exists */ + +/* ELF header */ +typedef struct { + +#define EI_NIDENT 16 + + /* first four characters are defined below */ +#define EI_MAG0 0 +#define ELFMAG0 0x7f +#define EI_MAG1 1 +#define ELFMAG1 'E' +#define EI_MAG2 2 +#define ELFMAG2 'L' +#define EI_MAG3 3 +#define ELFMAG3 'F' + +#define EI_CLASS 4 /* data sizes */ +#define ELFCLASS32 1 /* i386 -- up to 32-bit data sizes present */ + +#define EI_DATA 5 /* data type and ordering */ +#define ELFDATA2LSB 1 /* i386 -- LSB 2's complement */ + +#define EI_VERSION 6 /* version number. "e_version" must be the same */ +#define EV_CURRENT 1 /* current version number */ + +#define EI_PAD 7 /* from here in is just padding */ + + unsigned char e_ident[EI_NIDENT]; /* basic identification block */ + +#define ET_EXEC 2 /* we only care about executable types */ + Elf32_Half e_type; /* file types */ + +#define EM_386 3 /* i386 -- obviously use this one */ + Elf32_Half e_machine; /* machine types */ + Elf32_Word e_version; /* use same as "EI_VERSION" above */ + Elf32_Addr e_entry; /* entry point of the program */ + Elf32_Off e_phoff; /* program header table file offset */ + Elf32_Off e_shoff; /* section header table file offset */ + Elf32_Word e_flags; /* flags */ + Elf32_Half e_ehsize; /* elf header size in bytes */ + Elf32_Half e_phentsize; /* program header entry size */ + Elf32_Half e_phnum; /* number of entries in program header */ + Elf32_Half e_shentsize; /* section header entry size */ + Elf32_Half e_shnum; /* number of entries in section header */ + +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xff00 +#define SHN_LOPROC 0xff00 +#define SHN_HIPROC 0xff1f +#define SHN_ABS 0xfff1 +#define SHN_COMMON 0xfff2 +#define SHN_HIRESERVE 0xffff + Elf32_Half e_shstrndx; /* section header table index */ +} Elf32_Ehdr; + + +#define BOOTABLE_I386_ELF(h) \ + ((h.e_ident[EI_MAG0] == ELFMAG0) & (h.e_ident[EI_MAG1] == ELFMAG1) \ + & (h.e_ident[EI_MAG2] == ELFMAG2) & (h.e_ident[EI_MAG3] == ELFMAG3) \ + & (h.e_ident[EI_CLASS] == ELFCLASS32) & (h.e_ident[EI_DATA] == ELFDATA2LSB) \ + & (h.e_ident[EI_VERSION] == EV_CURRENT) & (h.e_type == ET_EXEC) \ + & (h.e_machine == EM_386) & (h.e_version == EV_CURRENT)) + + +/* symbol table - page 4-25, figure 4-15 */ +typedef struct +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +} Elf32_Sym; + +/* symbol type and binding attributes - page 4-26 */ + +#define ELF32_ST_BIND(i) ((i) >> 4) +#define ELF32_ST_TYPE(i) ((i) & 0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +/* symbol binding - page 4-26, figure 4-16 */ + +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +/* symbol types - page 4-28, figure 4-17 */ + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + + +/* Macros to split/combine relocation type and symbol page 4-32 */ + +#define ELF32_R_SYM(__i) ((__i)>>8) +#define ELF32_R_TYPE(__i) ((unsigned char) (__i)) +#define ELF32_R_INFO(__s, __t) (((__s)<<8) + (unsigned char) (__t)) + + +/* program header - page 5-2, figure 5-1 */ + +typedef struct { + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +} Elf32_Phdr; + +/* segment types - page 5-3, figure 5-2 */ + +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 + +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* segment permissions - page 5-6 */ + +#define PF_X 0x1 +#define PF_W 0x2 +#define PF_R 0x4 +#define PF_MASKPROC 0xf0000000 + + +/* dynamic structure - page 5-15, figure 5-9 */ + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +/* Dynamic array tags - page 5-16, figure 5-10. */ + +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 + diff --git a/shared_src/imgact_aout.h b/shared_src/imgact_aout.h new file mode 100644 index 000000000..a8b947d06 --- /dev/null +++ b/shared_src/imgact_aout.h @@ -0,0 +1,156 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)exec.h 8.1 (Berkeley) 6/11/93 + * $Id$ + */ +/* + * 11/23/95 - Kludge to get "ntohl" null macro added. -- ESB + * - and for __LDPGSZ + */ + +#ifndef _IMGACT_AOUT_H_ +#define _IMGACT_AOUT_H_ + +/* XXX ESB */ +#define ntohl(x) ((x << 24) | ((x & 0xFF00) << 8) \ + | ((x >> 8) & 0xFF00) | (x >> 24)) +#define htonl(x) ntohl(x) +#define __LDPGSZ 0x1000 + +#define N_GETMAGIC(ex) \ + ( (ex).a_midmag & 0xffff ) +#define N_GETMID(ex) \ + ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETMID_NET(ex) : \ + ((ex).a_midmag >> 16) & 0x03ff ) +#define N_GETFLAG(ex) \ + ( (N_GETMAGIC_NET(ex) == ZMAGIC) ? N_GETFLAG_NET(ex) : \ + ((ex).a_midmag >> 26) & 0x3f ) +#define N_SETMAGIC(ex,mag,mid,flag) \ + ( (ex).a_midmag = (((flag) & 0x3f) <<26) | (((mid) & 0x03ff) << 16) | \ + ((mag) & 0xffff) ) + +#define N_GETMAGIC_NET(ex) \ + (ntohl((ex).a_midmag) & 0xffff) +#define N_GETMID_NET(ex) \ + ((ntohl((ex).a_midmag) >> 16) & 0x03ff) +#define N_GETFLAG_NET(ex) \ + ((ntohl((ex).a_midmag) >> 26) & 0x3f) +#define N_SETMAGIC_NET(ex,mag,mid,flag) \ + ( (ex).a_midmag = htonl( (((flag)&0x3f)<<26) | (((mid)&0x03ff)<<16) | \ + (((mag)&0xffff)) ) ) + +#define N_ALIGN(ex,x) \ + (N_GETMAGIC(ex) == ZMAGIC || N_GETMAGIC(ex) == QMAGIC || \ + N_GETMAGIC_NET(ex) == ZMAGIC || N_GETMAGIC_NET(ex) == QMAGIC ? \ + ((x) + __LDPGSZ - 1) & ~(unsigned long)(__LDPGSZ - 1) : (x)) + +/* Valid magic number check. */ +#define N_BADMAG(ex) \ + (N_GETMAGIC(ex) != OMAGIC && N_GETMAGIC(ex) != NMAGIC && \ + N_GETMAGIC(ex) != ZMAGIC && N_GETMAGIC(ex) != QMAGIC && \ + N_GETMAGIC_NET(ex) != OMAGIC && N_GETMAGIC_NET(ex) != NMAGIC && \ + N_GETMAGIC_NET(ex) != ZMAGIC && N_GETMAGIC_NET(ex) != QMAGIC) + + +/* Address of the bottom of the text segment. */ +#define N_TXTADDR(ex) \ + ((N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC || \ + N_GETMAGIC(ex) == ZMAGIC) ? 0 : __LDPGSZ) + +/* Address of the bottom of the data segment. */ +#define N_DATADDR(ex) \ + N_ALIGN(ex, N_TXTADDR(ex) + (ex).a_text) + +/* Text segment offset. */ +#define N_TXTOFF(ex) \ + (N_GETMAGIC(ex) == ZMAGIC ? __LDPGSZ : (N_GETMAGIC(ex) == QMAGIC || \ + N_GETMAGIC_NET(ex) == ZMAGIC) ? 0 : sizeof(struct exec)) + +/* Data segment offset. */ +#define N_DATOFF(ex) \ + N_ALIGN(ex, N_TXTOFF(ex) + (ex).a_text) + +/* Relocation table offset. */ +#define N_RELOFF(ex) \ + N_ALIGN(ex, N_DATOFF(ex) + (ex).a_data) + +/* Symbol table offset. */ +#define N_SYMOFF(ex) \ + (N_RELOFF(ex) + (ex).a_trsize + (ex).a_drsize) + +/* String table offset. */ +#define N_STROFF(ex) (N_SYMOFF(ex) + (ex).a_syms) + +/* + * Header prepended to each a.out file. + * only manipulate the a_midmag field via the + * N_SETMAGIC/N_GET{MAGIC,MID,FLAG} macros in a.out.h + */ + +struct exec { + unsigned long a_midmag; /* htonl(flags<<26 | mid<<16 | magic) */ + unsigned long a_text; /* text segment size */ + unsigned long a_data; /* initialized data size */ + unsigned long a_bss; /* uninitialized data size */ + unsigned long a_syms; /* symbol table size */ + unsigned long a_entry; /* entry point */ + unsigned long a_trsize; /* text relocation size */ + unsigned long a_drsize; /* data relocation size */ +}; +#define a_magic a_midmag /* XXX Hack to work with current kern_execve.c */ + +/* a_magic */ +#define OMAGIC 0x107 /* 0407 old impure format */ +#define NMAGIC 0x108 /* 0410 read-only text */ +#define ZMAGIC 0x10b /* 0413 demand load format */ +#define QMAGIC 0xcc /* 0314 "compact" demand load format */ + +/* a_mid */ +#define MID_ZERO 0 /* unknown - implementation dependent */ +#define MID_SUN010 1 /* sun 68010/68020 binary */ +#define MID_SUN020 2 /* sun 68020-only binary */ +#define MID_I386 134 /* i386 BSD binary */ +#define MID_SPARC 138 /* sparc */ +#define MID_HP200 200 /* hp200 (68010) BSD binary */ +#define MID_HP300 300 /* hp300 (68020+68881) BSD binary */ +#define MID_HPUX 0x20C /* hp200/300 HP-UX binary */ +#define MID_HPUX800 0x20B /* hp800 HP-UX binary */ + +/* + * a_flags + */ +#define EX_PIC 0x10 /* contains position independant code */ +#define EX_DYNAMIC 0x20 /* contains run-time link-edit info */ +#define EX_DPMASK 0x30 /* mask for the above */ + +#endif /* !_IMGACT_AOUT_H_ */ diff --git a/shared_src/mb_header.h b/shared_src/mb_header.h new file mode 100644 index 000000000..675f390cd --- /dev/null +++ b/shared_src/mb_header.h @@ -0,0 +1,79 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * MultiBoot Header description + */ + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see below. */ + unsigned magic; + + /* Feature flags - see below. */ + unsigned flags; + + /* + * Checksum + * + * The above fields plus this one must equal 0 mod 2^32. + */ + unsigned checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + unsigned header_addr; + unsigned load_addr; + unsigned load_end_addr; + unsigned bss_end_addr; + unsigned entry_addr; +}; + +/* + * The entire multiboot_header must be contained + * within the first MULTIBOOT_SEARCH bytes of the kernel image. + */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_FOUND(addr, len) \ + (!((addr) & 0x3) && ((len) >= 12) && (*((int *)(addr)) == MULTIBOOT_MAGIC) \ + && !(*((unsigned *)(addr)) + *((unsigned *)(addr+4)) \ + + *((unsigned *)(addr+8))) \ + && (!(MULTIBOOT_AOUT_KLUDGE & *((int *)(addr+4))) || ((len) >= 32))) + +/* Magic value identifying the multiboot_header. */ +#define MULTIBOOT_MAGIC 0x1BADB002 + +/* + * Features flags for 'flags'. + * If a boot loader sees a flag in MULTIBOOT_MUSTKNOW set + * and it doesn't understand it, it must fail. + */ +#define MULTIBOOT_MUSTKNOW 0x0000FFFF + +/* currently unsupported flags... this is a kind of version number. */ +#define MULTIBOOT_UNSUPPORTED 0x0000FFFC + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* This flag indicates the use of the other fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + diff --git a/shared_src/mb_info.h b/shared_src/mb_info.h new file mode 100644 index 000000000..bd0bdf61f --- /dev/null +++ b/shared_src/mb_info.h @@ -0,0 +1,141 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * The structure type "mod_list" is used by the "multiboot_info" structure. + */ + +struct mod_list +{ + /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ + unsigned long mod_start; + unsigned long mod_end; + + /* Module command line */ + unsigned long cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + unsigned long pad; +}; + + +/* + * INT-15, AX=E820 style "AddressRangeDescriptor" + * ...with a "size" parameter on the front which is the structure size - 4, + * pointing to the next one, up until the full buffer length of the memory + * map has been reached. + */ + +struct AddrRangeDesc +{ + unsigned long size; + unsigned long BaseAddrLow; + unsigned long BaseAddrHigh; + unsigned long LengthLow; + unsigned long LengthHigh; + unsigned long Type; + + /* unspecified optional padding... */ +}; + +/* usable memory "Type", all others are reserved. */ +#define MB_ARD_MEMORY 1 + + +/* + * MultiBoot Info description + * + * This is the struct passed to the boot image. This is done by placing + * its address in the EAX register. + */ + +struct multiboot_info +{ + /* MultiBoot info version number */ + unsigned long flags; + + /* Available memory from BIOS */ + unsigned long mem_lower; + unsigned long mem_upper; + + /* "root" partition */ + unsigned long boot_device; + + /* Kernel command line */ + unsigned long cmdline; + + /* Boot-Module list */ + unsigned long mods_count; + unsigned long mods_addr; + + union + { + struct + { + /* (a.out) Kernel symbol table info */ + unsigned long tabsize; + unsigned long strsize; + unsigned long addr; + unsigned long pad; + } a; + + struct + { + /* (ELF) Kernel section header table */ + unsigned long num; + unsigned long size; + unsigned long addr; + unsigned long shndx; + } e; + } syms; + + /* Memory Mapping buffer */ + unsigned long mmap_length; + unsigned long mmap_addr; +}; + +/* + * Flags to be set in the 'flags' parameter above + */ + +/* is there basic lower/upper memory information? */ +#define MB_INFO_MEMORY 0x1 +/* is there a boot device set? */ +#define MB_INFO_BOOTDEV 0x2 +/* is the command-line defined? */ +#define MB_INFO_CMDLINE 0x4 +/* are there modules to do something with? */ +#define MB_INFO_MODS 0x8 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MB_INFO_AOUT_SYMS 0x10 +/* is there an ELF section header table? */ +#define MB_INFO_ELF_SHDR 0x20 + +/* is there a full memory map? */ +#define MB_INFO_MEM_MAP 0x40 + +/* + * The following value must be present in the EAX register. + */ + +#define MULTIBOOT_VALID 0x2BADB002 + diff --git a/shared_src/pc_slice.h b/shared_src/pc_slice.h new file mode 100644 index 000000000..a67337667 --- /dev/null +++ b/shared_src/pc_slice.h @@ -0,0 +1,202 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _PC_SLICE_H +#define _PC_SLICE_H + +/* + * These define the basic PC MBR sector characteristics + */ + +#define PC_MBR_SECTOR 0 + +#define PC_MBR_SIG_OFFSET 510 +#define PC_MBR_SIGNATURE 0xaa55 + +#define PC_SLICE_OFFSET 446 +#define PC_SLICE_MAX 4 + + +/* + * Defines to guarantee structural alignment. + */ + +#define PC_MBR_CHECK_SIG(mbr_ptr) \ + ( *( (unsigned short *) (((int) mbr_ptr) + PC_MBR_SIG_OFFSET) ) \ + == PC_MBR_SIGNATURE ) + +#define PC_MBR_SIG(mbr_ptr) \ + ( *( (unsigned short *) (((int) mbr_ptr) + PC_MBR_SIG_OFFSET) ) ) + +#define PC_SLICE_FLAG(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET \ + + (part << 4)) ) ) + +#define PC_SLICE_HEAD(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 1 \ + + (part << 4)) ) ) + +#define PC_SLICE_SEC(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 2 \ + + (part << 4)) ) ) + +#define PC_SLICE_CYL(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 3 \ + + (part << 4)) ) ) + +#define PC_SLICE_TYPE(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 4 \ + + (part << 4)) ) ) + +#define PC_SLICE_EHEAD(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 5 \ + + (part << 4)) ) ) + +#define PC_SLICE_ESEC(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 6 \ + + (part << 4)) ) ) + +#define PC_SLICE_ECYL(mbr_ptr, part) \ + ( *( (unsigned char *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 7 \ + + (part << 4)) ) ) + +#define PC_SLICE_START(mbr_ptr, part) \ + ( *( (unsigned long *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 8 \ + + (part << 4)) ) ) + +#define PC_SLICE_LENGTH(mbr_ptr, part) \ + ( *( (unsigned long *) (((int) mbr_ptr) + PC_SLICE_OFFSET + 12 \ + + (part << 4)) ) ) + + +/* + * PC flag types are defined here. + */ + +#define PC_SLICE_FLAG_NONE 0 +#define PC_SLICE_FLAG_BOOTABLE 0x80 + +/* + * Known PC partition types are defined here. + */ + +#define PC_SLICE_TYPE_NONE 0 +#define PC_SLICE_TYPE_FAT12 1 +#define PC_SLICE_TYPE_FAT16_LT32M 4 +#define PC_SLICE_TYPE_EXTENDED 5 +#define PC_SLICE_TYPE_FAT16_GT32M 6 +#define PC_SLICE_TYPE_EXT2FS 0x83 + + /* this next one is special, as it uses it's own partitioning scheme + to subdivide the PC partition from there */ +#define PC_SLICE_TYPE_BSD 0xa5 + + +/* + * *BSD-style disklabel & partition definitions. + * + * This is a subdivided slice of type 'PC_SLICE_TYPE_BSD', so all of + * these, except where noted, are relative to the slice in question. + */ + +#define BSD_LABEL_SECTOR 1 +#define BSD_LABEL_MAGIC 0x82564557 + +#define BSD_LABEL_MAG_OFFSET 0 +#define BSD_LABEL_MAG2_OFFSET 132 +#define BSD_LABEL_NPARTS_OFFSET 138 +#define BSD_LABEL_NPARTS_MAX 8 + +#define BSD_PART_OFFSET 148 + + +/* + * Defines to guarantee structural alignment. + */ + +#define BSD_LABEL_CHECK_MAG(l_ptr) \ + ( *( (unsigned long *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET) ) \ + == ( (unsigned long) BSD_LABEL_MAGIC ) ) + +#define BSD_LABEL_MAG(l_ptr) \ + ( *( (unsigned long *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET) ) ) + +#define BSD_LABEL_DTYPE(l_ptr) \ + ( *( (unsigned short *) (((int) l_ptr) + BSD_LABEL_MAG_OFFSET + 4) ) ) + +#define BSD_LABEL_NPARTS(l_ptr) \ + ( *( (unsigned short *) (((int) l_ptr) + BSD_LABEL_NPARTS_OFFSET) ) ) + +#define BSD_PART_LENGTH(l_ptr, part) \ + ( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET \ + + (part << 4)) ) ) + +#define BSD_PART_START(l_ptr, part) \ + ( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET + 4 \ + + (part << 4)) ) ) + +#define BSD_PART_FRAG_SIZE(l_ptr, part) \ + ( *( (unsigned long *) (((int) l_ptr) + BSD_PART_OFFSET + 8 \ + + (part << 4)) ) ) + +#define BSD_PART_TYPE(l_ptr, part) \ + ( *( (unsigned char *) (((int) l_ptr) + BSD_PART_OFFSET + 12 \ + + (part << 4)) ) ) + +#define BSD_PART_FRAGS_PER_BLOCK(l_ptr, part) \ + ( *( (unsigned char *) (((int) l_ptr) + BSD_PART_OFFSET + 13 \ + + (part << 4)) ) ) + +#define BSD_PART_EXTRA(l_ptr, part) \ + ( *( (unsigned short *) (((int) l_ptr) + BSD_PART_OFFSET + 14 \ + + (part << 4)) ) ) + + +/* possible values for the "DISKTYPE"... all essentially irrelevant + except for DTYPE_SCSI */ +#define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define DTYPE_MSCP 2 /* MSCP */ +#define DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define DTYPE_SCSI 4 /* SCSI */ +#define DTYPE_ESDI 5 /* ESDI interface */ +#define DTYPE_ST506 6 /* ST506 etc. */ +#define DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define DTYPE_HPFL 8 /* HP Fiber-link */ +#define DTYPE_FLOPPY 10 /* floppy */ + + +/* possible values for the *BSD-style partition type */ +#define FS_UNUSED 0 /* unused */ +#define FS_SWAP 1 /* swap */ +#define FS_V6 2 /* Sixth Edition */ +#define FS_V7 3 /* Seventh Edition */ +#define FS_SYSV 4 /* System V */ +#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define FS_V8 6 /* Eighth Edition, 4K blocks */ +#define FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define FS_MSDOS 8 /* MSDOS file system */ +#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define FS_OTHER 10 /* in use, but unknown/unsupported */ +#define FS_HPFS 11 /* OS/2 high-performance file system */ +#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */ +#define FS_BOOT 13 /* partition contains bootstrap */ + + +#endif /* _PC_SLICE_H */ + diff --git a/shared_src/shared.h b/shared_src/shared.h new file mode 100644 index 000000000..b1deb129b --- /dev/null +++ b/shared_src/shared.h @@ -0,0 +1,483 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * Generic defines to use anywhere + */ + +/* + * Integer sizes + */ + +#define MAXINT 0x7FFFFFFF + +/* + * This is the location of the raw device buffer. It is 31.5K + * in size. + */ + +#define BUFFERSEG 0x7000 +#define BUFFERADDR 0x70000 + +/* 512-byte scratch area */ +#define SCRATCHSEG 0x77e0 +#define SCRATCHADDR 0x77e00 + +/* + * BIOS disk defines + */ +#define BIOSDISK_SUBFUNC_READ 0x2 +#define BIOSDISK_SUBFUNC_WRITE 0x3 +#define BIOSDISK_ERROR_GEOMETRY 0x100 + +/* + * This is the location of the filesystem (not raw device) buffer. + * It is 32K in size, do not overrun! + */ + +#define FSYS_BUF 0x68000 + +/* + * Linux setup parameters + */ + +#define LINUX_STAGING_AREA 0x100000 +#define LINUX_SETUP 0x90000 +#define LINUX_SETUP_MAXLEN 0x1E00 +#define LINUX_KERNEL 0x10000 +#define LINUX_KERNEL_MAXLEN 0x7F000 +#define LINUX_SETUP_SEG 0x9020 +#define LINUX_INIT_SEG 0x9000 +#define LINUX_KERNEL_LEN_OFFSET 0x1F4 +#define LINUX_SETUP_LEN_OFFSET 0x1F1 +#define LINUX_SETUP_STACK 0x3FF4 + +#define CL_MY_LOCATION 0x92000 +#define CL_MY_END_ADDR 0x920FF +#define CL_MAGIC_ADDR 0x90020 +#define CL_MAGIC 0xA33F +#define CL_BASE_ADDR 0x90000 +#define CL_OFFSET 0x90022 + +/* + * General disk stuff + */ + +#define SECTOR_SIZE 0x200 +#define BIOS_FLAG_FIXED_DISK 0x80 + +#define BOOTSEC_LOCATION 0x7C00 +#define BOOTSEC_SIGNATURE 0xAA55 +#define BOOTSEC_BPB_OFFSET 0x3 +#define BOOTSEC_BPB_LENGTH 0x3B +#define BOOTSEC_PART_OFFSET 0x1BE +#define BOOTSEC_PART_LENGTH 0x40 +#define BOOTSEC_SIG_OFFSET 0x1FE + +/* + * GRUB specific information + * (in LSB order) + */ + +#define COMPAT_VERSION_MAJOR 1 +#define COMPAT_VERSION_MINOR 0 +#define COMPAT_VERSION ((COMPAT_VERSION_MINOR<<8)|COMPAT_VERSION_MAJOR) + +#define STAGE1_VER_MAJ_OFFS 0x1bc +#define STAGE1_INSTALLSEG 0x1ba +#define STAGE1_INSTALLADDR 0x1b8 +#define STAGE1_FIRSTLIST 0x1b0 + +#define STAGE2_VER_MAJ_OFFS 0x6 +#define STAGE2_INSTALLPART 0x8 +#define STAGE2_VER_STR_OFFS 0xc + + +/* + * defines for use when switching between real and protected mode + */ + +#define data32 .byte 0x66 +#define addr32 .byte 0x67 +#define CR0_PE_ON 0x1 +#define CR0_PE_OFF 0xfffffffe +#define PROT_MODE_CSEG 0x8 +#define PROT_MODE_DSEG 0x10 +#define PSEUDO_RM_CSEG 0x18 +#define PSEUDO_RM_DSEG 0x20 +#define STACKOFF 0x2000 - 0x10 +#define PROTSTACKINIT FSYS_BUF - 0x10 + + +/* + * Assembly code defines + * + * "EXT_C" is assumed to be defined in the Makefile by the configure + * command. + */ + +#define ENTRY(x) .globl EXT_C(x) ; EXT_C(x) ## : +#define VARIABLE(x) ENTRY(x) + + +#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */ +#define K_STATUS 0x64 /* keyboard status */ +#define K_CMD 0x64 /* keybd ctlr command (write-only) */ + +#define K_OBUF_FUL 0x01 /* output buffer full */ +#define K_IBUF_FUL 0x02 /* input buffer full */ + +#define KC_CMD_WIN 0xd0 /* read output port */ +#define KC_CMD_WOUT 0xd1 /* write output port */ +#define KB_OUTPUT_MASK 0xdd /* enable output buffer full interrupt + enable data line + enable clock line */ +#define KB_A20_ENABLE 0x02 + + +#ifndef ASM_FILE + + +/* + * Below this should be ONLY defines and other constructs for C code. + */ + + +static inline unsigned char +inb(unsigned short port) +{ + unsigned char data; + + __asm __volatile("inb %1,%0" : "=a" (data) : "d" (port)); + return data; +} + +static inline void +outb(unsigned short port, unsigned char val) +{ + __asm __volatile("outb %0,%1" : :"a" (val), "d" (port)); +} + + +/* multiboot stuff */ + +#include "mb_header.h" +#include "mb_info.h" + +extern char end[]; /* will be the end of the bss */ + +/* this function must be called somewhere... */ +void cmain(void) __attribute__ ((noreturn)); + +#define NULL ((void *) 0) + + +/* + * From "asm.S" + */ + +extern unsigned long install_partition; +extern unsigned long boot_drive; +extern char version_string[]; +extern char config_file[]; + +/* calls for direct boot-loader chaining */ +void chain_stage1(int segment, int offset, int part_table_addr) + __attribute__ ((noreturn)); +void chain_stage2(int segment, int offset) __attribute__ ((noreturn)); + +/* do some funky stuff, then boot linux */ +void linux_boot(void) __attribute__ ((noreturn)); + +/* booting a multiboot executable */ +void multi_boot(int start, int mbi) __attribute__ ((noreturn)); + +/* sets it to linear or wired A20 operation */ +void gateA20(int linear); + +/* memory probe routines */ +int get_memsize(int type); +int get_eisamemsize(void); +int get_mmap_entry(int buf, int cont); + +/* low-level timing info */ +int getrtsecs(void); + +/* low-level character I/O */ +void cls(void); +int getxy(void); /* returns packed values, LSB+1 is x, LSB is y */ +void gotoxy(int x, int y); + +/* displays an ASCII character. IBM displays will translate some + characters to special graphical ones */ +#define DISP_UL 218 +#define DISP_UR 191 +#define DISP_LL 192 +#define DISP_LR 217 +#define DISP_HORIZ 196 +#define DISP_VERT 179 +#define DISP_LEFT 0x1b +#define DISP_RIGHT 0x1a +#define DISP_UP 0x18 +#define DISP_DOWN 0x19 +void putchar(int c); + +/* returns packed BIOS/ASCII code */ +#define BIOS_CODE(x) ((x) >> 8) +#define ASCII_CHAR(x) ((x) & 0xFF) +#define KEY_LEFT 0x4B00 +#define KEY_RIGHT 0x4D00 +#define KEY_UP 0x4800 +#define KEY_DOWN 0x5000 +#define KEY_INSERT 0x5200 +#define KEY_DELETE 0x5300 +#define KEY_HOME 0x4700 +#define KEY_END 0x4F00 +#define KEY_PGUP 0x4900 +#define KEY_PGDN 0x5100 +int asm_getkey(void); + +/* returns 0 if non-ASCII character */ +#define getc() ASCII_CHAR(getkey()) + +/* like 'getkey', but doesn't wait, returns -1 if nothing available */ +int checkkey(void); + +/* sets text mode character attribute at the cursor position */ +#define ATTRIB_NORMAL 0x7 +#define ATTRIB_INVERSE 0x70 +void set_attrib(int attr); + +/* low-level disk I/O */ +int get_diskinfo(int drive); +int biosdisk(int subfunc, int drive, int geometry, + int sector, int nsec, int segment); + + +/* + * From "cmdline.c" + */ + +#ifndef _CMDLINE_C + +extern int fallback; +extern char commands[]; + +#endif /* _CMDLINE_C */ + +char *skip_to(int after_equal, char *cmdline); +void init_cmdline(void); +int enter_cmdline(char *script, char *heap); + + +/* + * From "char_io.c" + */ + +#ifndef _CHAR_IO_C + +int special_attribute; + +#endif /* _CHAR_IO_C */ + +#define ERR_NONE 0 +#define ERR_WONT_FIT (ERR_NONE + 1) +#define ERR_NO_DISK (ERR_WONT_FIT + 1) +#define ERR_READ (ERR_NO_DISK + 1) +#define ERR_WRITE (ERR_READ + 1) +#define ERR_GEOM (ERR_WRITE + 1) +#define ERR_OUTSIDE_PART (ERR_GEOM + 1) +#define ERR_BAD_PART_TABLE (ERR_OUTSIDE_PART + 1) +#define ERR_NO_PART (ERR_BAD_PART_TABLE + 1) +#define ERR_BAD_FILENAME (ERR_NO_PART + 1) +#define ERR_BAD_FILETYPE (ERR_BAD_FILENAME + 1) +#define ERR_FILE_NOT_FOUND (ERR_BAD_FILETYPE + 1) +#define ERR_FSYS_MOUNT (ERR_FILE_NOT_FOUND + 1) +#define ERR_FSYS_CORRUPT (ERR_FSYS_MOUNT + 1) +#define ERR_FILELENGTH (ERR_FSYS_CORRUPT + 1) +#define ERR_NUMBER_PARSING (ERR_FILELENGTH + 1) +#define ERR_DEV_FORMAT (ERR_NUMBER_PARSING + 1) +#define ERR_DEV_VALUES (ERR_DEV_FORMAT + 1) +#define ERR_EXEC_FORMAT (ERR_DEV_VALUES + 1) +#define ERR_BELOW_1MB (ERR_EXEC_FORMAT + 1) +#define ERR_BOOT_FEATURES (ERR_BELOW_1MB + 1) +#define ERR_BOOT_FAILURE (ERR_BOOT_FEATURES + 1) +#define ERR_NEED_KERNEL (ERR_BOOT_FAILURE + 1) +#define ERR_UNRECOGNIZED (ERR_NEED_KERNEL + 1) +#define ERR_BAD_GZIP_HEADER (ERR_UNRECOGNIZED + 1) +#define ERR_BAD_GZIP_DATA (ERR_BAD_GZIP_HEADER + 1) +#define ERR_BAD_VERSION (ERR_BAD_GZIP_DATA + 1) +#define MAX_ERR_NUM (ERR_BAD_VERSION + 1) + +/* returns packed BIOS/ASCII code */ +#define BIOS_CODE(x) ((x) >> 8) +#define ASCII_CHAR(x) ((x) & 0xFF) +#define KEY_LEFT 0x4B00 +#define KEY_RIGHT 0x4D00 +#define KEY_UP 0x4800 +#define KEY_DOWN 0x5000 +#define KEY_INSERT 0x5200 +#define KEY_DELETE 0x5300 +#define KEY_HOME 0x4700 +#define KEY_END 0x4F00 +#define KEY_PGUP 0x4900 +#define KEY_PGDN 0x5100 +int getkey(void); /* actually just calls asm_getkey and invalidates the + disk buffer */ + +void init_page(void); +void print_error(void); +char *convert_to_ascii(char *buf, int c, ...); +void printf(char *format, ... ); +int get_cmdline(char *prompt, char *commands, char *cmdline, int maxlen); +int tolower(int c); +int isspace(int c); +int strncat(char *s1, char *s2, int n); +int strcmp(char *s1, char *s2); +char *strstr(char *s1, char *s2); +int bcopy(char *from, char *to, int len); +int bzero(char *start, int len); +int get_based_digit(int c, int base); +int safe_parse_maxint(char **str_ptr, int *myint_ptr); +int memcheck(int start, int len); + + +/* + * From "gunzip.c" + */ + +#ifndef _GUNZIP_C + +extern int no_decompression; +extern int compressed_file; + +#endif /* _GUNZIP_C */ + +int gunzip_test_header(void); +int gunzip_read(int addr, int len); + + +/* + * From "disk_io.c" + */ + +#ifndef _DISK_IO_C + +#ifndef NO_FANCY_STUFF +/* instrumentation variables */ +extern void (*debug_fs)(int); +extern void (*debug_fs_func)(int); +#endif /* NO_FANCY_STUFF */ + +extern unsigned long current_drive; +extern unsigned long current_partition; + +extern int fsys_type; + +#ifndef NO_BLOCK_FILES +extern int block_file; +#endif /* NO_BLOCK_FILES */ + +extern long part_start; +extern long part_length; + +extern int current_slice; + +extern int buf_drive; +extern int buf_track; +extern int buf_geom; + +/* these are the current file position and maximum file position */ +extern int filepos; +extern int filemax; + +#endif /* _DISK_IO_C */ + +int rawread(int drive, int sector, int byte_offset, int byte_len, int addr); +int devread(int sector, int byte_offset, int byte_len, int addr); + +int set_device(char *device); /* this gets a device from the string and + places it into the global parameters */ +int open_device(void); +int make_saved_active(void); /* sets the active partition to the that + represented by the "saved_" parameters */ + +int open(char *filename); +int read(int addr, int len); /* if "length" is -1, read all the + remaining data in the file */ +int dir(char *dirname); /* list directory, printing all completions */ + +int bsd_bootdev(void); +void print_fsys_type(void); /* this prints stats on the currently + mounted filesystem */ +void print_completions(char *filename); /* this prints device and filename + completions */ +void copy_current_part_entry(int addr); /* copies the current partition data + to the desired address */ + + +/* + * From "boot.c" + */ + +/* for the entry address */ +typedef void +(*entry_func)(int, int, int, int, int, int) __attribute__ ((noreturn)); + +#ifndef _BOOT_C + +extern char *cur_cmdline; +extern entry_func entry_addr; + +#endif /* _BOOT_C */ + +void bsd_boot(int type, int bootdev) __attribute__ ((noreturn)); +int load_image(void); +int load_module(void); + + +/* + * From "common.c" + */ + + +#ifndef _COMMON_C + +/* + * Common BIOS/boot data. + */ + +extern struct multiboot_info mbi; +extern unsigned long saved_drive; +extern unsigned long saved_partition; +extern unsigned long saved_mem_upper; +extern int mem_map; + +/* + * Error variables. + */ + +extern int errnum; +extern char *err_list[]; + +#endif /* _COMMON_C */ + +void init_bios_info(void) __attribute__ ((noreturn)); + +#endif /* ASM_FILE */ diff --git a/shared_src/stage1_5.c b/shared_src/stage1_5.c new file mode 100644 index 000000000..de15dfbdb --- /dev/null +++ b/shared_src/stage1_5.c @@ -0,0 +1,42 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "shared.h" + +void +cmain(void) +{ + printf("\n\nGRUB loading, please wait...\n"); + + /* + * Here load the true second-stage boot-loader. + */ + + if (open(config_file) && read(0x8000, -1)) + chain_stage2(0, 0x8000); + + /* + * If not, then print error message and die. + */ + + print_error(); + + stop(); +} +