[BITS 16] ; We need 16-bit intructions for Real
mode
[ORG 0x7C00] ; The BIOS loads the boot sector into memory location
0x7C00
reset_drive:
mov ah, 0 ; RESET-command
int 13h ; Call interrupt 13h
or ah, ah ; Check for error code
jnz reset_drive ; Try again if ah != 0
;vc에서 /base 10000 로 헀기 때문에 여기서부터 메모리를 로드
; 해야 한다. ES:BX 로 1000:0000h 이기 때문에 아래처럼 한다.
mov ax, 1000h ; es:bx <-- 1000:0000h
mov es, ax
mov bx, 0h ; Destination address = 0000:1000
mov ah, 02h ; READ SECTOR-command
; 두번째 섹터부터 3칸섹터가 커널이미지 섹터다.
mov al, 3h ; Number of sectors to read = 1
mov ch, 0 ; Cylinder = 0
; 현재 첫번째섹터512 이며 두번째 섹터부터 3개 섹터가 커널이미지다
mov cl, 02h ; Sector = 2
mov dh, 0 ; Head = 0
int 13h ; Call interrupt 13h
or ah, ah ; Check for error code
jnz reset_drive ; Try again if ah != 0
A20Address: ; Set A20 Address line here
CLI
CALL enableA20
STI
JMP Continue
enableA20:
call enableA20o1
jnz short enableA20done
mov al,0d1h
out 64h,al
call enableA20o1
jnz short enableA20done
mov al,0dfh
out 60h,al
enableA20o1:
mov ecx,20000h
enableA20o1l:
jmp short $+2
in al,64h
test al,2
loopnz enableA20o1l
enableA20done:
ret
Continue:
cli ; Disable interrupts, we want to be alone
xor ax, ax
mov ds, ax ; Set DS-register to 0 - used by lgdt
lgdt [gdt_desc] ; Load the GDT descriptor
mov eax, cr0 ; Copy the contents of CR0 into EAX
or eax, 1 ; Set bit 0
mov cr0, eax ; Copy the contents of EAX into CR0
jmp 08h:clear_pipe ; Jump to code segment, offset clear_pipe
[BITS 32] ; We now need 32-bit instructions
clear_pipe:
mov ax, 10h ; Save data segment identifyer
mov ds, ax ; Move a valid data segment into the data segment register
mov ss, ax ; Move a valid data segment into the stack segment register
mov esp, 090000h ; Move the stack pointer to 090000h
; 10200h로 점프 200h는 vc로 링킹하면 기본 PE헤더(200h)를 붙여서 더했다.
; 10200h 즉 1000:0200h 로 점프
;jmp 1000:0200h
jmp 10200h
gdt: ; Address for the GDT
gdt_null: ; Null Segment
dd 0
dd 0
gdt_code: ; Code segment, read/execute, nonconforming
dw 0FFFFh
dw 0
db 0
db 10011010b
db 11001111b
db 0
gdt_data: ; Data segment, read/write, expand down
dw 0FFFFh
dw 0
db 0
db 10010010b
db 11001111b
db 0
gdt_end: ; Used to calculate the size of the GDT
gdt_desc: ; The GDT descriptor
dw gdt_end - gdt - 1 ; Limit (size)
dd gdt ; Address of the GDT
times 510-($-$$) db 0 ; Fill up the file with zeros
dw 0AA55h ; Boot sector identifyer
아래처럼 어셈블 하여 오브젝 부트로더 바이너리를 얻어내야
합니다.
nasm -f bin bootsect.asm -o bootsect.bin
다음은 부트로더와 커널 이미지를 합쳐서 하나의 부팅이미지로 만들어주는 makeboot.c
입니다. 따로 프로젝트를 만들어서 간단히 컴파일해서 makeboot.exe를 만들도록
합니다.
#include
int
main(int argnr, char *args[])
{
FILE
*output, *input;
int
i, bytes_read, sectors_read, bytes_from_file;
char
buffer[512];
if
(argnr < 4) {
printf("Invalid
number of parameters.\n\n");
printf("USAGE:
%s [output] [input 1] [input 2] ... [input n]\n", args[0]);
printf("Example:
%s a.img bootsect.bin kernel.bin");
exit(0);
}
output
= fopen(args[1], "r");
//
덮어 쓰기 할꺼냐고 물어보는 코든데 그냥 덮어쓰자. --
if
(output != NULL) {
buffer[0]
= 0;
}
fclose(output);
output
= fopen(args[1], "wb");
for
(i = 2; i < argnr; i++) {
input
= fopen(args[i], "rb");
if
(input == NULL) {
printf("Missing
input file %s. Aborting operation...", args[i]);
fclose(output);
exit(1);
}
bytes_read
= 512;
bytes_from_file
= 0;
sectors_read
= 0;
while(bytes_read
== 512 && !feof(input)) {
bytes_read
= fread(buffer, 1, 512, input);
if
(bytes_read == 0)
break;
if
(bytes_read != 512)
memset(buffer+bytes_read,
0, 512-bytes_read);
sectors_read++;
fwrite(buffer,
1, 512, output);
bytes_from_file
+= bytes_read;
}
printf("%d
sectors, %d bytes read from file %s...\n", sectors_read, bytes_from_file,
args[i]);
fclose(input);
}
fclose(output);
return
0;
}
다음은 커널 소스입니다.
//
bro (bro@shinbiro.com)2004-02-17 - initial ( vc dev envronment setting )
//
starting function
void
start()
{
char*
hello = "Hello OS!";
unsigned
char* vidmem = (unsigned char*)0xB8000;
while(
*hello != '\0' )
{
*vidmem++
= *hello++;
*vidmem++
= 7; // 문자 기본 속성
}
//
커널이 끝나면 안된다. 계속 돌아야한다.
for(;;);
}