如果在加载过程中出现了读错误,那么将会导致一个无限不可中断的循环,这时候就需要通过手工来重新 启动计算机。 ************************************************************************/ #include # for CONFIG_ROOT_RDONLY #include
SETUPSECS = 4 # default nr of setup-sectors BOOTSEG = 0x07C0 # original address of boot-sector INITSEG = DEF_INITSEG # we move boot here - out of the way SETUPSEG = DEF_SETUPSEG # setup starts here SYSSEG = DEF_SYSSEG # system loaded at 0x10000 (65536) SYSSIZE = DEF_SYSSIZE # system size: # of 16-byte clicks
# to be loaded ROOT_DEV = 0 # ROOT_DEV is now written by "build" SWAP_DEV = 0 # SWAP_DEV is now written by "build"
关于LODS指令:LODS 指令和STOS指令功能互逆,它将SI寄存器指向的主存单元的内容送至AL或 AX寄存器,并相应修改SI使其指向下一个元素。LODS指令不影响标志。相当于: mov ds:si al; si += 1; 这里其实其主要用处就是用disksizes表中的各个数据来测试每个磁道的扇区数目! ************************************************************************ ok_load_setup: movw $disksizes, %si # table of sizes to try
probe_loop: lodsb cbtw # extend to word
# ax = 36(第一轮),18,15,9,这里没有$的变量(sectors)表示内存位置。因此表示把ax寄存器 的值存入sectors位置处。 movw %ax, sectors cmpw $disksizes+4, %si jae got_sectors # If all else fails, try 9 xchgw %cx, %ax # cx = track and sector xorw %dx, %dx # drive 0, head 0 xorb %bl, %bl
movb setup_sects, %bh incb %bh shlb %bh # address after setup (es = cs) movw $0x0201, %ax # service 2, 1 sector int $0x13 jc probe_loop # try next value
/************************************************************************ 显示字符串:回车+"loading" ************************************************************************/ got_sectors: movw $INITSEG, %ax movw %ax, %es # set up es movb $0x03, %ah # read cursor pos xorb %bh, %bh int $0x10 movw $9, %cx movw $0x0007, %bx # page 0, attribute 7 (normal) movw $msg1, %bp movw $0x1301, %ax # write string, move cursor int $0x10 # tell the user we're loading..
/************************************************************************ 读取内核映像bvmlinux.out到1M处(小内存这里我们就暂时不考虑了) ************************************************************************/ movw $SYSSEG, %ax # ok, we've written the message, now movw %ax, %es # we want to load system (at 0x10000)
This routine loads the system at address 0x10000, making sure no 64kB boundaries are crossed. We try to load it as fast aspossible, loading whole tracks whenever we can.
es = starting address segment (normally 0x1000) ************************************************************************/ sread: .word 0 # sectors read of current track head: .word 0 # current head track: .word 0 # current track
read_it: movb setup_sects, %al # al=4 incb %al # al=5 movb %al, sread # sread=5 movw %es, %ax testw $0x0fff, %ax die: jne die # es must be at 64kB boundary
xorw %bx, %bx # bx is starting address within segment rp_read: /************************************************************************ lcall的说明,Far Calls in Real-Address Mode. When executing a far call in realaddress mode, the processor pushes the current value of both the CS and EIP registers on the stack for use as a return-instruction pointer. The processor then performs a [far branch] to the code segment and offset specified with the target operand for the called procedure.
The target operand specifies an absolute far address either directly with a pointer (ptr16:16 or ptr16:32) or indirectly with a memory location(m16:16 or m16:32). With the pointer method, the segment and offset of the called procedure is encoded in the instruction using a 4-byte (16-bit operand size) far address immediate. With the indirect method, the target operand specifies a memory location that contains a 4-byte (16-bit operand size) far address. The operand-size attribute determines the size of the offset(16 or 32 bits) in the far address. The far address is loaded directly into the CS and EIP registers. If the operand-size attribute is 16, the upper two bytes of the EIP register are cleared.
bad_rt: pushw %ax # save error code call print_all # ah = error, al = read xorb %ah, %ah xorb %dl, %dl int $0x13 addw $10, %sp popa jmp read_track
/************************************************************************ 打印子例程 print_all is for debugging purposes.
it will print out all of the registers. The assumption is that this is called from a routine, with a stack frame like
%dx %cx %bx %ax (error) ret <- %sp ************************************************************************/ print_all: movw $5, %cx # error code + 4 registers movw %sp, %bp print_loop: pushw %cx # save count left call print_nl # nl for readability cmpb $5, %cl jae no_reg # see if register name is needed
movw $0xe05 + 'A' - 1, %ax subb %cl, %al int $0x10 movb $'X', %al int $0x10 movb $':', %al int $0x10 no_reg: addw $2, %bp # next register call print_hex # print it popw %cx loop print_loop ret
print_nl: movw $0xe0d, %ax # CR int $0x10 movb $0xa, %al # LF int $0x10 ret
# print_hex is for debugging purposes, and prints the word # pointed to by ss:bp in hexadecimal.
print_hex: movw $4, %cx # 4 hex digits movw (%bp), %dx # load word into dx print_digit: rolw $4, %dx # rotate to use low 4 bits movw $0xe0f, %ax # ah = request andb %dl, %al # al = mask for nybble addb $0x90, %al # convert al to ascii hex daa # in only four instructions! adc $0x40, %al daa int $0x10 loop print_digit ret
/************************************************************************ 关闭马达子例程 This procedure turns off the floppy drive motor, so that we enter the kernel in a known state, and don't have to worry about it later. ************************************************************************/ kill_motor: movw $0x3f2, %dx xorb %al, %al outb %al, %dx ret