root/usr/src/grub/grub-0.97/stage2/nbloader.S
/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2000   Free Software Foundation, Inc.
 *
 *  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 <nbi.h>
#include <diskless_size.h>
                        
        .file   "nbloader.S"
        .text
        .code16
        
        /* Just a dummy entry */
.globl _start; _start:

        /*
         * netboot image header
         */

        .long   NBI_MAGIC
        .long   0x00000004
        /* load address of the first block  */
        .word   NBI_DEST_OFF
        .word   NBI_DEST_SEG
        /* start addr of the relocation code */
        .word   NBI_DEST_OFF + (relocate - _start)
        .word   NBI_DEST_SEG

        .long   0x04000004
        .long   NBI_DEST_ADDR + 0x0200
        .long   DISKLESS_SIZE
        .long   DISKLESS_SIZE

relocate:
        /*
         * This code is for now located at 0x10000.
         * Relocate the code in two steps:
         * 1. Copy the first 32k to 0x8000 and jump to the relocated area.
         * 2. Copy the rest to 0x10000 (0x8000 + 32k).
         */

        /* Copy the first 32k  */
        movw    $NBI_DEST_SEG, %ax
        movw    %ax, %ds
        movw    $RELOCATED_SEG, %ax
        movw    %ax, %es
        xorw    %si, %si
        xorw    %di, %di
        /* Always copy 32k bytes */
        movw    $0x4000, %cx

        cld
        rep
        movsw

        /* Jump to the relocated address */
        ljmp    $0, $(RELOCATED_ADDR + copy_rest - _start)

        /* Copy the rest */
copy_rest:
        /* Set %edx to the number of bytes */
        movl    $(DISKLESS_SIZE + 0x200 - 0x8000), %edx
        
copy_loop:
        /* Check the rest */
        orl     %edx, %edx
        jz      boot_stage2

        /* Copy by 32k, as that is easy to implement */
        movl    $0x8000, %ecx
        cmpl    %ecx, %edx
        jg      copy
        movl    %edx, %ecx
        
copy:
        /* Update the number of rest bytes */
        subl    %ecx, %edx

        /* Add 0x0800 (32k >> 4) into %es and %ds */
        movw    %es, %ax
        addw    $0x0800, %ax
        movw    %ax, %es
        movw    %ds, %ax
        addw    $0x800, %ax
        movw    %ax, %ds
        
        /* Zero the offsets */
        xorw    %si, %si
        xorw    %di, %di
        
        /* Use word-size copy */
        addw    $1, %cx
        shrw    $1, %cx

        /* The direction is already correct */
        rep
        movsw

        jmp     copy_loop

        /* Jump to the stage2 */
boot_stage2:
        ljmp    $0, $STAGE2_START_ADDR
        
        /* This ensures that the length of this image will be 1 sector */
        . = _start + 0x200 - 1
        .byte   0