计划读一读FreeBSD的源代码

来源:互联网 发布:天刀好看少女捏脸数据 编辑:程序博客网 时间:2024/06/08 14:01
/* * Copyright (c) 2008 Luigi Rizzo (mostly documentation) * Copyright (c) 2002 Bruce M. Simpson * Copyright (c) 1998 Robert Nordier * All rights reserved. * * Redistribution and use in source and binary forms are freely * permitted provided that the above copyright notice and this * paragraph and the following disclaimer are duplicated in all * such forms. * * This software is provided "AS IS" and without any express or * implied warranties, including, without limitation, the implied * warranties of merchantability and fitness for a particular * purpose. * * $FreeBSD: release/10.0.0/sys/boot/i386/boot0/boot0.S 228738 2011-12-20 15:19:29Z jhb $ *//* build options: */#ifdef SIO/* use serial console on COM1.*/#endif#ifdef PXE/* enable PXE/INT18 booting with F6 */#define SAVE_MORE_MEMORY#endif#ifdef CHECK_DRIVE/* make sure we boot from a HD. */#endif#ifdef ONLY_F_KEYS/* Only F1..F6, no digits on console */#endif#ifdef VOLUME_SERIAL/* support Volume serial number */#define B0_BASE0x1ae/* move the internal data area */#define SAVE_MEMORY#else#define B0_BASE0x1b2#endif#ifdef TEST/* enable some test code */#define SAVE_MEMORY#define SAVE_MORE_MEMORY#endif/* * Note - this code uses many tricks to save space and fit in one sector. * This includes using side effects of certain instructions, reusing * register values from previous operations, etc. * Be extremely careful when changing the code, even for simple things. *//* *BOOT BLOCK STRUCTURE * * This code implements a Master Boot Record (MBR) for an Intel/PC disk. * It is 512 bytes long and it is normally loaded by the BIOS (or another * bootloader) at 0:0x7c00. This code depends on %cs:%ip being 0:0x7c00 * * The initial chunk of instructions is used as a signature by external * tools (e.g. boot0cfg) which can manipulate the block itself. * * The area at offset 0x1b2 contains a magic string ('Drive '), also * used as a signature to detect the block, and some variables that can * be updated by boot0cfg (and optionally written back to the disk). * These variables control the operation of the bootloader itself, * e.g. which partitions to enable, the timeout, the use of LBA * (called 'packet') or CHS mode, whether to force a drive number, * and whether to write back the user's selection back to disk. * * As in every Master Boot Record, the partition table is at 0x1be, * made of four 16-byte entries each containing: * *   OFF SIZEDESCRIPTION *    0  1status (0x80: bootable, 0: non bootable) *    1  3start sector CHS *   8:head, 6:sector, 2:cyl bit 9..8, 8:cyl bit 7..0 *    4   1partition type *    5   3end sector CHS *    8   4LBA of first sector *   12   4partition size in sectors * * and followed by the two bytes 0x55, 0xAA (MBR signature). *//* *BOOT BLOCK OPERATION * * On entry, the registers contain the following values: * *%cs:%ip0:0x7c00 *%dldrive number (0x80, 0x81, ... ) *%sipointer to the partition table from which we were loaded. *Some boot code (e.g. syslinux) use this info to relocate *themselves, so we want to pass a valid one to the next stage. *NOTE: the use of %si is not a standard. * * This boot block first relocates itself at a different address (0:0x600), * to free the space at 0:0x7c00 for the next stage boot block. * * It then initializes some memory at 0:0x800 and above (pointed by %bp) * to store the original drive number (%dl) passed to us, and to construct a * fake partition entry. The latter is used by the disk I/O routine and, * in some cases, passed in %si to the next stage boot code. * * The variables at 0x1b2 are accessed as negative offsets from %bp. * * After the relocation, the code scans the partition table printing * out enabled partition or disks, and waits for user input. * * When a partition is selected, or a timeout expires, the currently * selected partition is used to load the next stage boot code, * %dl and %si are set appropriately as when we were called, and * control is transferred to the newly loaded code at 0:0x7c00. *//* *CONSTANTS * * NHRDRV is the address in segment 0 where the BIOS writes the *total number of hard disks in the system. * LOAD is the original load address and cannot be changed. * ORIGIN is the relocation address. If you change it, you also need * to change the value passed to the linker in the Makefile * PRT_OFF is the location of the partition table (from the MBR standard). * B0_OFF is the location of the data area, known to boot0cfg so *it cannot be changed. Computed as a negative offset from 0x200 * MAGIC is the signature of a boot block. */.set NHRDRV,0x475# Number of hard drives.set ORIGIN,0x600# Execution address.set LOAD,0x7c00# Load address.set PRT_OFF,0x1be# Partition table.set B0_OFF,(B0_BASE-0x200)# Offset of boot0 data.set MAGIC,0xaa55# Magic: bootable.set KEY_ENTER,0x1c# Enter key scan code.set KEY_F1,0x3b# F1 key scan code.set KEY_1,0x02# #1 key scan code.set ASCII_BEL,'#'# ASCII code for <BEL>.set ASCII_CR,0x0D# ASCII code for <CR>/* * Offsets of variables in the block at B0_OFF, and in the volatile * data area, computed as displacement from %bp. * We need to define them as constant as the assembler cannot * compute them in its single pass. */.set _NXTDRV,B0_OFF+6# Next drive.set _OPT,B0_OFF+7# Default option.set _SETDRV,B0_OFF+8# Drive to force.set _FLAGS,B0_OFF+9# Flags.set SETDRV,0x20# the 'setdrv' flag.set NOUPDATE,0x40# the 'noupdate' flag.set USEPACKET,0x80# the 'packet' flag/* ticks is at a fixed position */.set _TICKS,(PRT_OFF - 0x200 - 2)# Timeout ticks.set _MNUOPT, 0x10# Saved menu entries.set TLEN, (desc_ofs - bootable_ids)# size of bootable ids.globl start# Entry point.code16# This runs in real mode/* * MAIN ENTRY POINT * Initialise segments and registers to known values. * segments start at 0. * The stack is immediately below the address we were loaded to. * NOTE: the initial section of the code (up to movw $LOAD,%sp) * is used by boot0cfg, together with the 'Drive ' string and * the 0x55, 0xaa at the end, as an identifier for version 1.0 * of the boot code. Do not change it. * In version 1.0 the parameter table (_NEXTDRV etc) is at 0x1b9 */start:cld# String ops incxorw %ax,%ax# Zeromovw %ax,%es# Addressmovw %ax,%ds#  datamovw %ax,%ss# Set upmovw $LOAD,%sp#  stack/* * Copy this code to the address it was linked for, 0x600 by default. */movw %sp,%si# Sourcemovw $start,%di# Destinationmovw $0x100,%cx# Word countrep# Relocatemovsw#  code/* * After the code, (i.e. at %di+0, 0x800) create a partition entry, * initialized to LBA 0 / CHS 0:0:1. * Set %bp to point to the partition and also, with negative offsets, * to the variables embedded in the bootblock (nextdrv and so on). */movw %di,%bp# Address variablesmovb $0x8,%cl# Words to clearrep# Zerostosw#  themincb -0xe(%di)# Set the S field to 1jmp main-LOAD+ORIGIN# Jump to relocated codemain:#if defined(SIO) && COMSPEED != 0/* * Init the serial port. bioscom preserves the driver number in DX. */movw $COMSPEED,%ax# defined by Makefilecallw bioscom#endif/* * If the 'setdrv' flag is set in the boot sector, use the drive * number from the boot sector at 'setdrv_num'. * Optionally, do the same if the BIOS gives us an invalid number * (note though that the override prevents booting from a floppy * or a ZIP/flash drive in floppy emulation). * The test costs 4 bytes of code so it is disabled by default. */testb $SETDRV,_FLAGS(%bp)# Set drive number?#ifndef CHECK_DRIVE/* disable drive checks */jz save_curdrive# no, use the default#elsejnz disable_update# Yestestb %dl,%dl# Drive number valid?js save_curdrive# Possibly (0x80 set)#endif/* * Disable updates if the drive number is forced. */disable_update:orb $NOUPDATE,_FLAGS(%bp)# Disable updatesmovb _SETDRV(%bp),%dl# Use stored drive number/* * Whatever drive we decided to use, store it at (%bp). The byte * is normally used for the state of the partition (0x80 or 0x00), * but we abuse it as it is very convenient to access at offset 0. * The value is read back after 'check_selection' */save_curdrive:movb %dl, (%bp)# Save drive numberpushw %dx# Also in the stack#ifdefTEST/* test code, print internal bios drive */rolb $1, %dlmovw $drive, %sicall putkey#endifcallw putn# Print a newline/* * Start out with a pointer to the 4th byte of the first table entry * so that after 4 iterations it's beyond the end of the sector * and beyond a 256 byte boundary. We use the latter trick to check for * end of the loop without using an extra register (see start.5). */movw $(partbl+0x4),%bx# Partition table (+4)xorw %dx,%dx# Item number/* * Loop around on the partition table, printing values until we * pass a 256 byte boundary. */read_entry:movb %ch,-0x4(%bx)# Zero active flag (ch == 0)btw %dx,_FLAGS(%bp)# Entry enabled?jnc next_entry# Nomovb (%bx),%al# Load typetest %al, %al# skip empty partitionjz next_entry/* * Scan the table of bootable ids, which starts at %di and has * length TLEN. On a match, %di points to the element following the * match; the corresponding offset to the description is $(TLEN-1) * bytes ahead. We use a count of TLEN+1 so if we don't find a match * within the first TLEN entries, we hit the 'unknown' entry. */movw $bootable_ids,%di# Lookup tablesmovb $(TLEN+1),%cl# Number of entriesrepne# Locatescasb#  type/* * Get the matching element in the next array. * The byte at $(TLEN-1)(%di) contains the offset of the description * string from %di, so we add the number and print the string. */addw $(TLEN-1), %di# Adjustmovb (%di),%cl# Partitionaddw %cx,%di#  descriptioncallw putx# Display itnext_entry:incw %dx# Next itemaddb $0x10,%bl# Next entryjnc read_entry# Till done/* * We are past a 256 byte boundary: the partition table is finished. * Add one to the drive number and check it is valid. * Note that if we started from a floppy, %dl was 0 so we still * get an entry for the next drive, which is the first Hard Disk. */popw %ax# Drive numbersubb $0x80-0x1,%al# Does nextcmpb NHRDRV,%al#  drive exist? (from BIOS?)jb print_drive# Yes/* * If this is the only drive, don't display it as an option. */decw %ax# Already drive 0?jz print_prompt# Yes/* * If it was illegal or we cycled through them, go back to drive 0. */xorb %al,%al# Drive 0/* * Whatever drive we selected, make it an ascii digit and save it * back to the "nxtdrv" location in case we want to save it to disk. * This digit is also part of the printed drive string, so add 0x80 * to indicate end of string. */print_drive:addb $'0'|0x80,%al# Save nextmovb %al,_NXTDRV(%bp)#  drive numbermovw $drive,%di# Displaycallw putx#  item/* * Menu is complete, display a prompt followed by current selection. * 'decw %si' makes the register point to the space after 'Boot: ' * so we do not see an extra CRLF on the screen. */print_prompt:movw $prompt,%si# Displaycallw putstr#  promptmovb _OPT(%bp),%dl# Displaydecw %si#  defaultcallw putkey#  keyjmp start_input# Skip beep/* * Here we have the code waiting for user input or a timeout. */beep:movb $ASCII_BEL,%al# Input error, print or beepcallw putchrstart_input:/* * Actual Start of input loop.  Take note of time */xorb %ah,%ah# BIOS: Getint $0x1a#  system timemovw %dx,%di# Ticks whenaddw _TICKS(%bp),%di#  timeoutread_key:/* * Busy loop, looking for keystrokes but keeping one eye on the time. */#ifndef SIOmovb $0x1,%ah# BIOS: Checkint $0x16#  for keypress#else /* SIO */movb $0x03,%ah# BIOS: Read COMcall bioscomtestb $0x01,%ah# Check line status# (bit 1 indicates input)#endif /* SIO */jnz got_key # Have inputxorb %ah,%ah# BIOS: int 0x1a, 00int $0x1a#  get system timecmpw %di,%dx# Timeout?jb read_key# No/* * Timed out or default selection */use_default:movb _OPT(%bp),%al# Load defaultorb $NOUPDATE,_FLAGS(%bp) # Disable updatesjmp check_selection# Join common code/* * Get the keystroke. * ENTER or CR confirm the current selection (same as a timeout). * Otherwise convert F1..F6 (or '1'..'6') to 0..5 and check if the * selection is valid. * The SIO code uses ascii chars, the console code uses scancodes. */got_key:#ifndef SIOxorb %ah,%ah# BIOS: int 0x16, 00int $0x16#  get keypressmovb %ah,%al# move scan code to %alcmpb $KEY_ENTER,%al#elsemovb $0x02,%ah# BIOS: Receivecall bioscomcmpb $ASCII_CR,%al#endifje use_default# enter -> default/* * Check if the key is acceptable, and loop back if not. * The console (non-SIO) code looks at scancodes and accepts * both F1..F6 and 1..6 (the latter costs 6 bytes of code), * relying on the fact that F1..F6 have higher scancodes than 1..6 * The SIO code only takes 1..6 */#ifdef SIO /* SIO mode, use ascii values */subb $'1',%al# Subtract '1' ascii code#else /*  console mode -- use scancodes */subb $KEY_F1,%al/* Subtract F1 scan code */#if !defined(ONLY_F_KEYS)cmpb $0x5,%al# F1..F6jna 3f# Yessubb $(KEY_1 - KEY_F1),%al# Less #1 scan code3:#endif /* ONLY_F_KEYS */#endif /* SIO */check_selection:cmpb $0x5,%al# F1..F6 or 1..6 ?#ifdef PXE /* enable PXE/INT18 using F6 */jne 1f;int $0x18# found F6, try INT181:#endif /* PXE */jae beep# Not in F1..F5, beep/* * We have a selection.  If it's a bad selection go back to complain. * The bits in MNUOPT were set when the options were printed. * Anything not printed is not an option. */cbtw# Extend (%ah=0 used later)btw %ax,_MNUOPT(%bp) # Option enabled?jnc beep# No/* * Save the info in the original tables * for rewriting to the disk. */movb %al,_OPT(%bp)# Save option/* * Make %si and %bx point to the fake partition at LBA 0 (CHS 0:0:1). * Because the correct address is already in %bp, just use it. * Set %dl with the drive number saved in byte 0. * If we have pressed F5 or 5, then this is a good, fake value * to present to the next stage boot code. */movw %bp,%si# Partition for writemovb (%si),%dl# Drive number, saved abovemovw %si,%bx# Partition for readcmpb $0x4,%al# F5/#5 pressed?pushf# Save results for laterje 1f# Yes, F5/* * F1..F4 was pressed, so make %bx point to the currently * selected partition, and leave the drive number unchanged. */shlb $0x4,%al# Point toaddw $partbl,%ax#  selectedxchgw %bx,%ax #  partitionmovb $0x80,(%bx)# Flag active/* * If not asked to do a write-back (flags 0x40) don't do one. * Around the call, save the partition pointer to %bx and * restore to %si which is where the next stage expects it. */1:pushw %bx# Savetestb $NOUPDATE,_FLAGS(%bp)# No updates?jnz 2f# skip updatemovw $start,%bx# Data to writemovb $0x3,%ah# Write sectorcallw intx13#  to disk2:popw %si# Restore/* * If going to next drive, replace drive with selected one. * Remember to un-ascii it. Hey 0x80 is already set, cool! */popf# Restore %al test resultsjne 3f# If not F5/#5movb _NXTDRV(%bp),%dl# Next drivesubb $'0',%dl#  number/* * Load selected bootsector to the LOAD location in RAM. If read * fails or there is no 0x55aa marker, treat it as a bad selection. */3:movw $LOAD,%bx# Address for readmovb $0x2,%ah# Read sectorcallw intx13#  from diskjc beep# If errorcmpw $MAGIC,0x1fe(%bx)# Bootable?jne beep# Nopushw %si# Save ptr to selected part.callw putn# Leave some spacepopw %si# Restore, next stage uses itjmp *%bx# Invoke bootstrap/* * Display routines * putkeyprints the option selected in %dl (F1..F5 or 1..5) followed by *the string at %si * putx:print the option in %dl followed by the string at %di *also record the drive as valid. * putn:print a crlf * putstr:print the string at %si * putchr:print the char in al *//* * Display the option and record the drive as valid in the options. * That last point is done using the btsw instruction which does * a test and set. We don't care for the test part. */putx:btsw %dx,_MNUOPT(%bp)# Enable menu optionmovw $item,%si# Displaycallw putkey#  keymovw %di,%si# Display the restcallw putstr# Display stringputn:movw $crlf,%si# To next linejmp putstrputkey:#ifndef SIOmovb $'F',%al# Displaycallw putchr#  'F'#endifmovb $'1',%al# Prepareaddb %dl,%al#  digitputstr.1:callw putchr# Display charputstr:lodsb# Get bytetestb $0x80,%al # End of string?jz putstr.1# Noandb $~0x80,%al # Clear MSB then print last putchr:#ifndef SIOpushw %bx# Savemovw $0x7,%bx # Page:attributemovb $0xe,%ah# BIOS: Displayint $0x10#  characterpopw %bx# Restore#else /* SIO */movb $0x01,%ah# BIOS: Sendbioscom:pushw %dx# Savexorw %dx,%dx # Use COM1int $0x14#  Characterpopw %dx# Restore#endif /* SIO */retw# To caller/* One-sector disk I/O routine *//* * %dl: drive, %si partition entry, %es:%bx transfer buffer. * Load the CHS values and possibly the LBA address from the block * at %si, and use the appropriate method to load the sector. * Don't use packet mode for a floppy. */intx13:# Prepare CHS parametersmovb 0x1(%si),%dh# Load headmovw 0x2(%si),%cx# Load cylinder:sectormovb $0x1,%al# Sector countpushw %si# Savemovw %sp,%di# Save#ifndef CHECK_DRIVE/* floppy support */testb %dl, %dl# is this a floppy ?jz 1f# Yes, use CHS mode#endiftestb $USEPACKET,_FLAGS(%bp)# Use packet interface?jz 1f# Nopushl $0x0# Set thepushl 0x8(%si)# LBA addresspushw %es# Set the transferpushw %bx#  buffer addresspush  $0x1# Block countpush  $0x10# Packet sizemovw %sp,%si# Packet pointerdecw %ax# Verify offorb $0x40,%ah# Use disk packet1:int $0x13# BIOS: Disk I/Omovw %di,%sp# Restorepopw %si# Restoreretw# To caller/* * Various menu strings. 'item' goes after 'prompt' to save space. * Also use shorter versions to make room for the PXE/INT18 code. */prompt:#ifdef PXE.ascii "\nF6 PXE\r"#endif.ascii "\nBoot:"item:.ascii " ";     .byte ' '|0x80crlf:.ascii "\r";     .byte '\n'|0x80/* Partition type tables */bootable_ids:/* * These values indicate bootable types we know about. * Corresponding descriptions are at desc_ofs: * Entries don't need to be sorted. */.byte 0x83, 0xa5, 0xa6, 0xa9, 0x06, 0x07, 0x0b#ifndef SAVE_MORE_MEMORY.byte 0x05# extended partition#endif#ifndef SAVE_MEMORY/* other DOS partitions */.byte 0x01# FAT12.byte 0x04# FAT16 < 32M#endifdesc_ofs:/* * Offsets that match the known types above, used to point to the * actual partition name. The last entry must point to os_misc, * which is used for non-matching names. */.byte os_linux-.# 131, Linux.byte os_freebsd-.# 165, FreeBSD.byte os_bsd-.# 166, OpenBSD.byte os_bsd-.# 169, NetBSD.byte os_dos-.#   6, FAT16 >= 32M.byte os_win-.#   7, NTFS.byte os_win-.#  11, FAT32#ifndef SAVE_MORE_MEMORY.byte os_ext-.#   5, DOS Ext#endif#ifndef SAVE_MEMORY.byte os_dos-.#   1, FAT12 DOS.byte os_dos-.#   4, FAT16 <32M#endif.byte os_misc-. # Unknown/* * And here are the strings themselves. The last byte of * the string has bit 7 set. */os_misc:.byte '?'|0x80os_dos:#ifndef SAVE_MORE_MEMORY/* 'DOS' remapped to 'WIN' if no room */.ascii "DO";   .byte 'S'|0x80#endifos_win:.ascii "Wi";   .byte 'n'|0x80os_linux:.ascii "Linu"; .byte 'x'|0x80os_freebsd:.ascii "Free"os_bsd:.ascii "BS";   .byte 'D'|0x80#ifndef SAVE_MORE_MEMORYos_ext:.ascii "EX";   .byte 'T'|0x80#endif.org (0x200 + B0_OFF),0x90/* * The boot0 version 1.0 parameter table. * Do not move it nor change the "Drive " string, boot0cfg * uses its offset and content to identify the boot sector. * The other fields are sometimes changed before writing back to the drive * Be especially careful that nxtdrv: must come after drive:, as it * is part of the same string. */drive:.ascii "Drive "nxtdrv:.byte 0x0# Next drive numberopt:.byte 0x0# Optionsetdrv_num:.byte 0x80# Drive to forceflags:.byte FLAGS# Flags#ifdef VOLUME_SERIAL.byte 0xa8,0xa8,0xa8,0xa8       # Volume Serial Number#endifticks:.word TICKS# Delay.org PRT_OFF/* * Here is the 64 byte partition table that fdisk would fiddle with. */partbl:.fill 0x40,0x1,0x0# Partition table.word MAGIC# Magic number.org 0x200# again, safety checkendblock:

        最近总是计划FreeBSD的源代码,先上代码吧!
0 0
原创粉丝点击