2012-03-13 62 views
2

我是新手OS設計,到目前爲止設計了一個「操作系統」(真的只是一個啓動扇區),並決定嘗試製作一個獨特的啓動加載程序和「內核」(仍然非常簡單) 。我的問題很簡單,但通過谷歌搜索和搜索這個網站,我設法避開了我(好吧,我找到了一個類似的問題,但答案是模糊/先進的以便我能夠使用它)。從CD加載扇區

我看過int 0x13 AH = 02,但是使用了曲目,我不認爲它使用了CD。我看到某處應該使用擴展讀扇區(AH = 0x42),但我不知道如何使用它,因爲我沒有看到我可以指定要讀取哪個扇區以及扇區應該放在RAM中的位置。

這裏是一個問題:如何從使用El Torito沒有模擬的CD加載扇區。如果你能以「最簡單的形式」提出答案,並試着提供一些代碼,我將不勝感激,因爲我是新手。提前致謝!

編輯:

我不知道,如果你需要它,但我使用NASM語法,因此,如果你能給我在NASM的答案,那將是巨大的。

+0

你有鏈接到其他問題嗎? – sarnold 2012-03-13 01:56:17

+0

在這裏:http://stackoverflow.com/questions/856050/how-to-load-kernel-into-memory-from-cd-rom-using-assembly-nasm – Codesmith 2012-03-13 01:58:24

+0

二十年前太久未能準確記住,但我很確定從來沒有支持讀取光驅的16位BIOS。 – 2012-03-13 02:01:42

回答

3

按照慣例,BIOS會將您應該用於int 13h的驅動器號放入DL寄存器。然後,您可以使用int 13h,ax = 4B01h(獲取仿真狀態)來確定磁盤信息,並使用int 13x函數42h讀取帶有LBA字段中的扇區號的0x800大小的CD扇區。檢查ISOLINUX bootloader瞭解更多詳情。入口點是_start,讀取扇區的例程是getlinsec_cdrom

編輯:讀取有關如何使用它的int 13h擴展the documentation。基本上,您需要傳遞一個填充結構,以及放置讀取數據的緩衝區的扇區號,計數和地址。

+0

有兩個問題,我該如何告訴CPU放置扇區的位置,我使用ES:BX還是別的?此外,這是否在16位真實模式下工作? – Codesmith 2012-03-13 22:19:56

+0

另外,如何告訴計算機要讀取哪個扇區?它仍然是Cl? – Codesmith 2012-03-13 22:27:06

+0

編輯完美后。謝謝! – Codesmith 2012-03-14 00:45:06

0

我的啓動裝載程序認爲它裝載在0x07c0:0x000而不是0x0000:0x7c00。但它的工作。我正在使用GNU工具。

這是大會:


/** 
* This is the first stage bootloader. It is used to loader the second 
* stage bootloader. 
*/ 



# The address of this bootloader been loaded by BIOS 
.equ BOOTLOADER_ADDR, 0x07c0 

# The signature for bootloader. 
.equ BOOT_MACHINE_SIGNATURE, 0xaa55 

# The offset of the start of BPB (BIOS Parameter Block). 
.equ BOOT_MACHINE_BPB_START, 0x03 

# The offset of the end of BPB (BIOS Parameter Block). 
.equ BOOT_MACHINE_BPB_END, 0x5a 

# The offset of the end of the partition table. 
.equ BOOT_MACHINE_PART_END, 0x1fe 

/* The segment of disk buffer. The disk buffer MUST be 32K long and 
    cannot straddle a 64K boundary. */ 
.equ BOOT_MACHINE_BUFFER_SEG, 0x7000 

.macro PRINT str 
     pusha 
     movw $\str, %si 
     call print 
     popa 
.endm 

.macro DUMP begin, size 
     movw $\begin, %si 
     movw $\size, %cx 
     call dump 
.endm 

.macro RESET_DISK drive 
     pusha 
     movb $\drive, %dl 
     movw 0x0, %ah 
     call reset_disk 
     popa 
.endm 

.macro READ_SECTORS drive, head, cylinder, sector, count, destination 
     pusha 
     movw $\destination, %ax 
     movw %ax, %es 
     xorw %bx, %bx 
     movb $\drive, %dl 
     movb $\head, %dh 
     movb $\cylinder, %ch 
     movb $\sector, %cl 
     movb $\count, %al 
     call read_sectors 
     popa 
.endm 

/** 
* Entry point 
*/ 
     .file "boot.S" 
     .text 
     .code16 
     .org 0x0000 
.globl _start, start; 
_start: 
start: 
# The offset 0x0000 must be a jump to the reset of code. 
     jmp after_BPB 
     nop 
     . = _start + BOOT_MACHINE_BPB_START 
     . = _start + 4 
disk_addr_packet: 
     .byte 0x10    # (00h) size of packet 
     .byte 0x00    # (01h) reserved 
     .word 0x0001   # (02h) number of blocks to transfer 
     .word 0x8000, 0x0000 # (04h) DWORD, transfer buffer 
     .word 0x0010, 0x0000 # (08h) QWORD, starting absolute block number 
     .word 0x0000, 0x0000 
           # (10h) 
     . = _start + BOOT_MACHINE_BPB_END 
after_BPB: 
     cli        # disable interrupt. 
     movw $BOOTLOADER_ADDR, %ax  # set address expression 
     movw %ax, %ds 
     movw %ax, %es 
     # movw $BOOTLOADER_ADDR, %sp # stack grows down to 0x0000 
     PRINT message_booting 

# We need make sure the BIOS supports the INT 13 extensions. 
int13_ext_check: 
     mov $0x41, %ah 
     mov $0x55aa, %bx 
     # DL should contain the drive value. But we'd better save it. 
     push %dx 
     int $0x13 
     jc int13_ext_check_failed 
     cmpw $0xaa55, %bx 
     jne int13_ext_check_failed 
     andw $0x001, %cx  # if function 42h-44h,47h,48h are supported 
     jz int13_ext_check_failed 
     jmp read_cd_content 

int13_ext_check_failed: 
     PRINT message_no_int13_ext 
     jmp loop 

read_cd_content: 

     # CHS mode : Cylinder-Head-Sector mode. 
     # LBA mode : Logical Block Addressing mode. 
     # When we use INT 13 extension, we use LBA mode in which 
     # the device is taken as a single large device. 

     PRINT message_loading_img 
     pop %dx 
     movw $disk_addr_packet, %si 
     movb $0x42, %ah 
     int $0x13 
     jc error_read_sectors 

     DUMP 0x0400, 16 
     jmp loop 

error_read_sectors: 
     PRINT message_sector_read_err 
     jmp loop 
loop: 
     PRINT message_halt 
     cli 
     hlt 
     jmp loop 
message_booting: 
     .asciz "Booting ...\r\n" 
message_halt: 
     .asciz "Boot Halt.\r\n" 
message_no_int13_ext: 
     .asciz "No INT13 extension. Boot failed.\r\n" 
message_loading_img: 
     .asciz "Loading OS image.\r\n" 
message_sector_read_err: 
     .asciz "Sector read error.\r\n" 
hexdump: 
     .byte 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 

/** 
* Write the string pointed to by %si 
* Each char is wrote by using BIOS INT 0x10. 
* BIOS INT 0x10: 
* AH = 0x0e 
* AL = Character to write. 
* BH = Page Number (Should be 0) 
* BL = Foreground color (Graphics Modes Only) 
* When using the function, put the string address to SI. The string 
* should end with 0. 
*/ 
1: 
     movw $0x0001, %bx 
     movb $0xe, %ah 
     int $0x10 
print: 
     lodsb # Loads a byte pointed by SI into AL. 
     cmpb $0, %al 
     jne 1b 
     ret 

/** 
* Print the register's value. 
* 
print_reg: 

/** 
* Dump a area of data. 
* Display 8 bytes of code each line. For every 10 line will wait for any key to continue. 
* SI = The start address 
* CX = The size of area to dump 
*/ 
index: 
.byte '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' 
.byte 'A', 'B', 'C', 'D', 'E', 'F' 
enter_key: 
.asciz "\r\n" 
1: 
     ret 
dump: 
     movb $10, %dl   # DL = row counter, DH = column counter. 
     movb $8, %dh 
     cld 
2: 
     cmpw $0, %cx 
     je 1b 
     xorw %ax, %ax   # clean the AX at first. 
     lodsb     # loads the byte pointed by SI into AL. 
     push %ax    # because AH will be used, so we save AX. 
     shr $4, %ax    # show first 4 bits. 
     movw $index, %di 
     addw %ax, %di 
     movb (%di), %al 
     movb $0xe, %ah 
     movw $0x0001, %bx  # Page number = 0, froeground color = 1. 
     int $0x10 
     pop %ax 
     andw $0x000f, %ax  # show last 4 bits. 
     movw $index, %di 
     addw %ax, %di 
     movb (%di), %al 
     movb $0xe, %ah 
     movw $0x0001, %bx 
     int $0x10 
     movb $' ', %al   # display a space 
     movb $0xe, %ah 
     movw $0x0001, %bx 
     int $0x10 
     dec %cx 
     dec %dh 
     jnz 2b 
     PRINT enter_key 
     movb $8,%dh 
     jmp 2b 

/** 
* Reset the disk controller, let it go to the first sector. 
* BIOS INT 0x13 
* AH = 0x00 
* DL = Drive to reset. 
* Return: 
* AH = Status code. 
* CF = Clear if success, set if failure. 
*/ 
reset_disk: 
     int $0x13 
     jc reset_disk 
     ret 

/** 
* Read sectors into memory 
* BIOS INT 0x13 
* AH = 0x02 
* AL = Numbers of sectors to read. 
* CH = Low eight bits of cylinder number. 
* CL = Sector Number Bits 0-5. Bits 6-7 are for hard disks only. 
* DH = Head number. 
* DL = Drive number (Bit 7 set for hard disk) 
* ES:BX = Buffer to read sector to 
* Return 
* AH = Status code 
* AL = Number of sectors read 
* CF = Set if failure, cleaned if successful. 
*/ 
read_sectors: 
     int $0x13 
     jc read_sectors 
     ret 

     .fill 0x1fe - (. - _start) ,1,0 
     .org _start + BOOT_MACHINE_PART_END 
     .word BOOT_MACHINE_SIGNATURE 

是Makefile:

 
all: 
     i686-elf-as -o boot.o boot.S 
     i686-elf-ld --oformat=binary -Ttext=0x0 -o boot.bin boot.o 

# Make fd is for test only, our target media is CD. 
fd: all 
     dd status=noxfer conv=notrunc if=boot.bin of=floppy.flp 
     qemu-system-i386 -fda floppy.flp 

cd: all 
     mkdir -p iso/boot 
     cp boot.bin iso/boot/loader.sys 
     mkisofs -R -J -c boot/bootcat \ 
       -b boot/loader.sys -no-emul-boot -boot-load-size 4 \ 
       -input-charset utf-8 \ 
       -o ./boot.iso ./iso 
     qemu-system-i386 -cdrom boot.iso 

clean: 
     @rm -rf iso boot.o boot.bin floppy.flp boot.iso 

關鍵是要理解如何賽格:偏移表示在實模式地址。

+0

許多BIOS使用0x0000:0x7c00作爲跳轉到的位置。這樣的跳轉設置CS = 0x0000和IP = 0x7c00。某些BIOS(包括QEMU中的那個)會跳轉到0x07c0:0x0000,因此CS = 0x07c0和IP = 0x0000。 – 2015-11-29 14:49:52

+0

0x07c0:0x0000 =(0x07c0 << 4)+0 = 0x07c00物理地址。 0x0000:0x7c00 =(0x0000 << 4)+ 7c00 = 0x07c00物理地址。兩者都映射到相同的位置。 BIOS可跳轉到映射到0x07c00的任何段:偏移量。 (所以你不能依賴_CS_作爲一個特定的值)Bootloader代碼不應該依賴於_CS_(當然是_DS_,_ES_)中的值。你只需要將它們設置爲你的代碼需要的東西。您使用的段取決於原點/偏移量(-Ttext確定)。 -Ttext = 0要求將_DS_設置爲0x07c0。 -Ttext = 0x7c00要求_DS_爲0.無論你使用哪一個。 – 2015-11-29 14:53:54

+0

如果您編寫需要接近絕對間接跳轉的引導加載程序代碼(您的代碼不需要,只需指出它),那麼CS實際上需要正確設置。通常通過在代碼中跳轉到標籤來完成。在代碼* _after_BPB *中,您可以添加'jmp $ BOOTLOADER_ADDR,$ .mainjmp',後跟標籤'.mainjmp:'。這實際上會遠遠地跳到下一個指令。現在的副作用是_CS_將會是BOOTLOADER_ADDR(0x07c0).AI表示,不適用於您編寫的代碼。僅指出任何人可能會好奇如何將CS設置爲特定值 – 2015-11-29 15:12:48