2012-03-13 10 views
2

저는 OS 디자인을 처음 접했고 지금까지는 하나의 "OS"(실제로는 단일 부트 섹터)를 설계했으며 고유 한 부트 로더와 "커널"(여전히 간단 함)을 만들기로했습니다. . 내 질문은 간단하지만 아직 인터넷 검색을 통해 나를 피하고이 사이트를 검색 할 수있었습니다. (좋아요, 비슷한 질문을 하나 발견했지만 대답은 모호하고/고급으로 사용할 수있었습니다).섹터로드 CD

나는 0x13 AH = 02를 보았지만, 트랙을 사용한다. 나는 CD의 사용을 생각하지 않는다. 나는 확장 된 읽기 섹터 (AH = 0x42)를 사용해야하는 곳을 보았습니다. 그러나 그것을 읽는 방법을 알지 못합니다. 왜냐하면 어떤 섹터를 읽을 지, 그리고 섹터가 RAM에 있어야 하는지를 알 수 없기 때문입니다. .

다음은 질문입니다. El Torito 에뮬레이션을 사용하는 CD에서 섹터를 어떻게로드합니까? 만약 당신이 '가장 단순한 형식'으로 답을 넣을 수 있다면 고맙겠습니다. 그리고 새로운 코드 인 것처럼 약간의 코드를 제공하려고합니다. 미리 감사드립니다!

편집 :

당신이 그것을 필요로하는 경우에 나도 몰라,하지만 난 NASM 구문을 사용하고, 그래서 당신은 나에게 NASM에서 답을 줄 수 있다면, 그것은 좋은 것입니다.

+0

다른 질문에 대한 링크가 있으면 편리합니까? – sarnold

+0

바로 여기 : http://stackoverflow.com/questions/856050/how-to-load-kernel-into-memory-from-cd-rom-using-assembly-nasm – Codesmith

+0

20 년 전에 너무 정확하게 기억하고 있으며, 하지만 나는 CD-ROM 드라이브를 읽는 것을 지원하는 16 비트 BIOS가 결코 없었을 것이라고 확신한다. –

답변

3

일반적으로 BIOS는 int 13h에 사용해야하는 드라이브 번호를 DL 레지스터에 넣습니다. 그런 다음 int 13h, ax = 4B01h (에뮬레이션 상태 가져 오기)를 사용하여 디스크 정보를 확인하고 int 13x function 42h를 사용하여 LBA 필드의 섹터 번호가있는 0x800 크기의 CD 섹터를 읽을 수 있습니다. 자세한 내용은 ISOLINUX bootloader을 확인하십시오. 진입 점은 _start이고 섹터를 읽는 루틴은 getlinsec_cdrom입니다.

편집 : 사용 방법에 대해서는 the documentation에서 int 13h 확장을 읽으십시오. 기본적으로 읽기 데이터를 저장할 버퍼의 섹터 번호, 개수 및 주소가 채워진 구조체를 전달해야합니다.

+0

두 가지 질문은 섹터를 넣을 CPU를 어떻게 지정합니까? ES : BX 또는 다른 것을 사용합니까? 또한 16 비트 리얼 모드에서도 작동합니까? – Codesmith

+0

또한 컴퓨터에 어떤 섹터를 읽을 지 어떻게 말합니까? 아직도 Cl입니까? – Codesmith

+0

편집 후 완벽합니다. 감사! – Codesmith

0

내 부트 로더가 0x0000 : 0x7c00이 아닌 0x07c0 : 0x000에로드되었다고 생각합니다. 그러나 그것은 효과적이다. 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 

이것은 메이크입니다 : 리얼 모드의 주소를 나타냅니다 오프셋 :

 
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의 BIOS 포함)는 0x07c0 : 0x0000으로 점프하므로 CS = 0x07c0 및 IP = 0x0000입니다. –

+0

0x07c0 : 0x0000 = (0x07c0 << 4) +0 = 0x07c00 실제 주소. 0x0000 : 0x7c00 = (0x0000 << 4) + 7c00 = 0x07c00 물리적 주소. 둘 다 같은 위치에 매핑됩니다. BIOS는 0x07c00으로 매핑되는 모든 세그먼트 (세그먼트)로 이동할 수 있습니다. (따라서 특정 값인 _CS_에 의존 할 수 없습니다.) 부트 로더 코드는 _CS_ (물론 _DS_, _ES_)의 값에 의존하면 안됩니다. 코드를 필요로하는 수준으로 설정하면됩니다. 사용하는 세그먼트는 원점/오프셋에 따라 다릅니다 (-T 텍스트에 의해 결정됨). -T 텍스트 = 0은 _DS_이 0x07c0으로 설정되어야합니다. -Ttext = 0x7c00은 _DS_가 0이어야합니다. 사용하는 것은 중요하지 않습니다. –

+0

거의 절대 간접 점프를 필요로하는 부트 로더 코드를 작성한 경우 (코드가이를 가리 키지 않는 경우) CS를 실제로 올바르게 설정해야합니다. 이는 대개 코드의 레이블로 멀리 이동하여 수행됩니다. * _after_BPB * 코드에서'jmp $ BOOTLOADER_ADDR, $ .mainjmp' 뒤에'.mainjmp :'레이블을 붙일 수 있습니다. 이것은 문자 그대로 다음 명령어로 점프 할 것입니다. 부작용은 이제 _CS_가 BOOTLOADER_ADDR (0x07c0)이 될 것입니다. 당신이 작성한 코드에는 적용되지 않습니다. 호기심을 유발할만한 누군가를 가리 키기 만하면됩니다. CS를 특정 값으로 설정 –