69eead77ff
The CD now boots directly from the ISO 9660 filesystem instead of using MBR partitioning with Minix file systems. This saves some space on the CD and reduces memory requirements by some unknown amount as the root ramdisk is completely eliminated. The x86 hard drive image creation is also rewritten in the same fashion. The setup is modified to be more NetBSD-like (unpacking sets tarballs instead of blindly copying the CD contents). Splitting MINIX into sets is done in another commit due to it being a nightmare to rebase. Since MINIX lacks union mounts for now, a bunch of ramdisks are generated at run-time to make parts of the filesystem writeable for the CD. This solution isn't ideal, but it's enough for an installation CD. Change-Id: Icbd9cca4dafebf7b42c345b107a17679a622d5cd
364 lines
9.2 KiB
ArmAsm
364 lines
9.2 KiB
ArmAsm
/* $NetBSD: cdboot.S,v 1.12 2011/01/04 16:53:05 jakllsch Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 2005 The NetBSD Foundation, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
* by Bang Jun-Young.
|
|
*
|
|
* 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.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
|
*/
|
|
|
|
/*
|
|
* This is a primary boot loader that loads a secondary boot loader
|
|
* directly from CD without performing floppy/hard disk emulation as
|
|
* described by the El Torito specification.
|
|
*/
|
|
|
|
#include <machine/asm.h>
|
|
#include <sys/bootblock.h>
|
|
|
|
#define BOOT_ADDR 0x7c00
|
|
#define BLOCK_SIZE 2048 /* Default for ISO 9660 */
|
|
#define VD_LBA 16 /* LBA of Volume Descriptor (VD) */
|
|
#define PVD_ADDR end /* Where Primary VD is loaded */
|
|
#define ROOTDIR_ADDR end+BLOCK_SIZE /* Where Root Directory is loaded */
|
|
#define LOADER_ADDR SECONDARY_LOAD_ADDRESS
|
|
|
|
#ifdef BOOT_FROM_FAT
|
|
#define MBR_AFTERBPB 90 /* BPB size in FAT32 partition BR */
|
|
#else
|
|
#define MBR_AFTERBPB 62 /* BPB size in floppy master BR */
|
|
#endif
|
|
|
|
/*
|
|
* See src/sys/sys/bootblock.h for details.
|
|
*/
|
|
#define MBR_PART_COUNT 4
|
|
#define MBR_PART_OFFSET 446
|
|
#define MBR_PART_SIZE 16 /* sizeof(struct mbr_partition) */
|
|
|
|
/*
|
|
* Disk error codes
|
|
*/
|
|
#define ERROR_TIMEOUT 0x80
|
|
|
|
/*
|
|
* Volume Descriptor types.
|
|
*/
|
|
#define VD_PRIMARY 1
|
|
#define VD_SUPPLEMENTARY 2
|
|
#define VD_TERMINATOR 255
|
|
|
|
/* Only actually used entries are listed below */
|
|
|
|
/*
|
|
* Format of Primary Volume Descriptor (8.4)
|
|
*/
|
|
#define PVD_ROOT_DR 156 /* Offset of Root Directory Record */
|
|
|
|
/*
|
|
* Format of Directory Record (9.1)
|
|
*/
|
|
#define DR_LEN 0
|
|
#define DR_EXTENT 2
|
|
#define DR_DATA_LEN 10
|
|
#define DR_NAME_LEN 32
|
|
#define DR_NAME 33
|
|
|
|
.text
|
|
.code16
|
|
ENTRY(start)
|
|
jmp start1
|
|
|
|
. = start + MBR_AFTERBPB /* skip BPB */
|
|
. = start + MBR_DSN_OFFSET
|
|
.long 0
|
|
|
|
/* mbr_bootsel_magic (not used here) */
|
|
. = start + MBR_BS_MAGIC_OFFSET
|
|
.word 0
|
|
|
|
. = start + MBR_PART_OFFSET
|
|
. = start + MBR_MAGIC_OFFSET
|
|
pbr_magic:
|
|
.word MBR_MAGIC
|
|
.fill 512 /* reserve space for disklabel */
|
|
start1:
|
|
jmp 1f
|
|
.balign 4
|
|
.long X86_BOOT_MAGIC_1 /* checked by installboot & pbr code */
|
|
boot_params: /* space for patchable variables */
|
|
.long 1f - boot_params /* length of this data area */
|
|
#include <boot_params.S>
|
|
. = start1 + 0x80 /* Space for patching unknown params */
|
|
|
|
1: xorw %ax, %ax
|
|
movw %ax, %ds
|
|
movw %ax, %es
|
|
movw %ax, %ss
|
|
movw $BOOT_ADDR, %sp
|
|
movw %sp, %si
|
|
movw $start, %di
|
|
movw $BLOCK_SIZE/2, %cx
|
|
rep
|
|
movsw
|
|
ljmp $0, $real_start
|
|
|
|
real_start:
|
|
movb %dl, boot_drive /* Save boot drive number */
|
|
|
|
#ifndef DISABLE_KEYPRESS
|
|
/*
|
|
* We can skip boot wait when:
|
|
* - there's no hard disk present.
|
|
* - there's no active partition in the MBR of the 1st hard disk.
|
|
*/
|
|
|
|
/*
|
|
* Check presence of hard disks.
|
|
*/
|
|
movw $0x475, %si
|
|
movb (%si), %al
|
|
testb %al, %al
|
|
jz boot_cdrom
|
|
|
|
/*
|
|
* Find the active partition from the MBR.
|
|
*/
|
|
movw $0x0201, %ax /* %al = number of sectors to read */
|
|
movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
|
|
movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
|
|
/* %cl = high 2 bits of cyl no & */
|
|
/* sector number */
|
|
movw $0x0080, %dx /* %dh = head number */
|
|
/* %dl = disk number */
|
|
int $0x13 /* Read MBR into memory */
|
|
jc boot_cdrom /* CF set on error */
|
|
|
|
movb $1, mbr_loaded
|
|
movb $MBR_PART_COUNT, %cl
|
|
movw $BOOT_ADDR+MBR_PART_OFFSET, %si
|
|
1:
|
|
movb (%si), %al
|
|
testb $0x80, %al
|
|
jnz found_active
|
|
addw $MBR_PART_SIZE, %si
|
|
decb %cl
|
|
testb %cl, %cl
|
|
jnz 1b /* If 0, no active partition found */
|
|
jmp boot_cdrom
|
|
|
|
found_active:
|
|
movw $str_press_key, %si
|
|
call message
|
|
next_second:
|
|
movw $str_dot, %si
|
|
call message
|
|
decb wait_count
|
|
jz boot_hard_disk
|
|
xorb %ah, %ah /* Get system time */
|
|
int $0x1a
|
|
movw %dx, %di /* %cx:%dx = number of clock ticks */
|
|
addw $19, %di /* 19 ~= 18.2 Hz */
|
|
wait_key:
|
|
movb $1, %ah /* Check for keystroke */
|
|
int $0x16
|
|
jz not_avail /* ZF clear if keystroke available */
|
|
xorb %ah, %ah /* Read key to flush keyboard buf */
|
|
int $0x16
|
|
jmp boot_cdrom
|
|
not_avail:
|
|
xorb %ah, %ah /* Get system time */
|
|
int $0x1a
|
|
cmpw %dx, %di /* Compare with saved time */
|
|
jnz wait_key
|
|
jmp next_second
|
|
|
|
boot_hard_disk:
|
|
movw $str_crlf, %si
|
|
call message
|
|
cmpb $1, mbr_loaded
|
|
jz 1f
|
|
movw $0x0201, %ax /* %al = number of sectors to read */
|
|
movw $BOOT_ADDR, %bx /* %es:%bx = data buffer */
|
|
movw $0x0001, %cx /* %ch = low 8 bits of cylinder no */
|
|
/* %cl = high 2 bits of cyl no & */
|
|
/* sector number */
|
|
movw $0x0080, %dx /* %dh = head number */
|
|
/* %dl = disk number */
|
|
int $0x13 /* Read MBR into memory */
|
|
jc panic /* CF set on error */
|
|
1:
|
|
movw %cs, %ax /* Restore initial state */
|
|
movw %ax, %ds
|
|
movw %ax, %es
|
|
movw $0x0080, %dx /* %dl = boot drive number */
|
|
jmp $0, $BOOT_ADDR /* Jump to MBR! */
|
|
jmp panic /* This should be never executed */
|
|
#endif /* !DISABLE_KEYPRESS */
|
|
|
|
boot_cdrom:
|
|
movw $str_banner, %si
|
|
call message
|
|
|
|
/* Read volume descriptor sectors until Primary decriptor found */
|
|
movl $VD_LBA, %eax
|
|
next_block:
|
|
movb $1, %dh /* Number of sectors to read */
|
|
movl $PVD_ADDR, %ebx
|
|
call read_sectors
|
|
cmpb $VD_PRIMARY, (%bx) /* Is it Primary Volume Descriptor? */
|
|
jz pvd_found
|
|
incl %eax
|
|
cmpb $VD_TERMINATOR, (%bx)
|
|
jnz next_block
|
|
movw $str_no_pvd, %si
|
|
call message
|
|
jmp panic
|
|
|
|
/* Read all of root directory */
|
|
pvd_found:
|
|
movw $PVD_ADDR+PVD_ROOT_DR, %bx
|
|
movl DR_EXTENT(%bx), %eax /* LBA of the root directory */
|
|
movl DR_DATA_LEN(%bx), %edx
|
|
shrl $11, %edx /* Convert to number of sectors */
|
|
movb %dl, %dh /* ... and load it to %dh */
|
|
movl $ROOTDIR_ADDR, %ebx
|
|
call read_sectors
|
|
|
|
/* Scan directory entries searching for /boot */
|
|
next_entry:
|
|
cmpb $0, DR_LEN(%bx)
|
|
jz last_entry
|
|
movw %bx, %si
|
|
addw $DR_NAME, %si
|
|
movb DR_NAME_LEN(%bx), %cl
|
|
movw $str_loader, %di
|
|
1:
|
|
movb (%si), %al
|
|
cmpb %al, (%di)
|
|
jnz fail
|
|
incw %si
|
|
incw %di
|
|
decb %cl
|
|
jnz 1b
|
|
jmp load_loader
|
|
fail:
|
|
addw DR_LEN(%bx), %bx
|
|
jmp next_entry
|
|
last_entry:
|
|
movw $str_no_loader, %si
|
|
call message
|
|
jmp panic
|
|
|
|
/* Found /boot, read contents to 0x1000:0 */
|
|
load_loader:
|
|
movl DR_EXTENT(%bx), %eax
|
|
movl DR_DATA_LEN(%bx), %edx
|
|
addl $(BLOCK_SIZE-1), %edx /* Convert file length to */
|
|
shrl $11, %edx /* ... number of sectors */
|
|
movb %dl, %dh
|
|
movl $LOADER_ADDR, %ebx
|
|
call read_sectors
|
|
|
|
/* Finally call into code of /boot */
|
|
movl $boot_params, %esi /* Provide boot_params */
|
|
xorl %edx, %edx
|
|
movb boot_drive, %dl
|
|
xorl %ebx, %ebx /* Zero sector number */
|
|
lcall $LOADER_ADDR/16, $0
|
|
/* fall through on load failure */
|
|
panic:
|
|
hlt
|
|
jmp panic
|
|
|
|
/*
|
|
* Read disk sector(s) into memory
|
|
*
|
|
* %eax = LBA of starting sector
|
|
* %ebx = buffer to store sectors
|
|
* %dh = number of sectors to read
|
|
*
|
|
* Long transfers are split onto multiple 64k reads
|
|
*/
|
|
#define MAX_SECTORS (0x10000/BLOCK_SIZE)
|
|
read_sectors:
|
|
pushal
|
|
movl %eax, edd_lba
|
|
shrl $4, %ebx /* Convert buffer addr to seg:0 */
|
|
movw %bx, edd_segment
|
|
1: movb %dh, edd_nsecs
|
|
cmpb $MAX_SECTORS, %dh
|
|
jle 2f /* j if less than 64k */
|
|
movb $MAX_SECTORS, edd_nsecs /* Read 32 sectors - 64k bytes */
|
|
2: movb boot_drive, %dl
|
|
movw $edd_packet, %si
|
|
read_again:
|
|
movb $0x42, %ah
|
|
push %dx /* bios shouldn't kill %dh, but ... */
|
|
int $0x13
|
|
pop %dx /* ... better safe than sorry! */
|
|
jc read_fail
|
|
addw $0x1000, edd_segment /* Advance segment addr by 64k bytes */
|
|
addl $MAX_SECTORS, edd_lba /* And sector number to match */
|
|
sub edd_nsecs, %dh /* Number of sectors remaining */
|
|
jnz 1b
|
|
popal
|
|
ret
|
|
|
|
read_fail:
|
|
cmpb $ERROR_TIMEOUT, %ah
|
|
jz read_again
|
|
movw $str_read_error, %si
|
|
call message
|
|
jmp panic
|
|
|
|
#include <message.S>
|
|
|
|
edd_packet:
|
|
edd_len: .word 16
|
|
edd_nsecs: .word 0 /* Number of sectors to transfer */
|
|
edd_offset: .word 0
|
|
edd_segment: .word 0
|
|
edd_lba: .quad 0
|
|
|
|
wait_count: .byte 6
|
|
boot_drive: .byte 0
|
|
mbr_loaded: .byte 0
|
|
|
|
str_banner: .ascii "\r\nNetBSD/x86 cd9660 Primary Bootstrap"
|
|
str_crlf: .asciz "\r\n"
|
|
str_press_key: .asciz "\r\nPress any key to boot from CD"
|
|
str_dot: .asciz "."
|
|
str_read_error: .asciz "Can't read CD"
|
|
str_no_pvd: .asciz "Can't find Primary Volume Descriptor"
|
|
str_no_loader: .asciz "Can't find /minixboot"
|
|
str_loader: .asciz "MINIXBOOT.;1"
|
|
|
|
/* Used to calculate free bytes */
|
|
free_space = end - .
|
|
|
|
. = start + BLOCK_SIZE
|
|
end:
|