GeekOS 소스 분석(3) - setup.asm
GeekOS 소스 분석(3) - setup.asm
작성자 : 강대명
작성일 : 2004-05-11
GeekOS Setup 파일입니다. 여기서 보호모드로 뛰어 넘어서 Entry 로 지정되었다
main.c 의 main 함수로 점프하게 됩니다.
; GeekOS setup code
; Copyright (c) 2001, David H. Hovemeyer <daveho at cs.umd.edu>
; $Revision: 1.16 $
; This is free software. You are permitted to use,
; redistribute, and modify it as specified in the file "COPYING".
; A lot of this code is adapted from Kernel Toolkit 0.2
; and Linux version 2.2.x, so the following copyrights apply:
; Copyright (C) 1991, 1992 Linus Torvalds
; modified by Drew Eckhardt
; modified by Bruce Evans (bde)
; adapted for Kernel Toolkit by Luigi Sgro
%include "defs.asm"
아직까지는 16bit 리얼모드 코드입니다.
[BITS 16]
[ORG 0x0]
start_setup:
; Redefine the data segment so we can access variables
; declared in this file.
mov ax, SETUPSEG
mov ds, ax
; Use int 15h to find out size of extended memory in KB.
; Extended memory is the memory above 1MB. So by
; adding 1MB to this amount, we get the total amount
; of system memory. We can only detect 64MB this way,
; but that's OK for now.
이 부분은 메모리 사이즈를 가져오는 방법입니다. 현재 GeekOS는 64M 까지
판별이 가능하다고 합니다. 오재준님의 방법을 쓰면 그 이상의 메모리 크기도
가져오도록 수정이 가능합니다. 수정한 코드가 일단 날라가서 나중에 추가하
도록
하죠 ^^ - 오재준님의 "OS 제작의 완성"을 읽어보시길
xor eax, eax
mov ah, 0x88
int 0x15
add eax, 1024 ; 1024 KB == 1 MB
mov [mem_size_kbytes], eax
//Linux 초창기 커널 코드에서도 많이 모이는 모터를 끄는 루틴입니다.
; Kill the floppy motor.
call Kill_Motor
; Block interrupts, since we can't meaningfully handle them yet
; and we no longer need BIOS services.
//인터럽트를 금지시킵니다.
cli
//약식으로 보호모드로 넘어가기 위한 GDT 와 IDT를 설정합니다. IDT는
인터럽트가 발생했을 때 그것을 처리하는 Interrupt Description Table을 말하고
GDT 는 Global Description Table 로 가상 주소를 물리 주소로 바꾸기 위한 세그먼트가
저장된다. 이걸로 유저 영역과 커널 영역의 주소가 구분되고 권한이 구분된다고 보면된다.
; Set up IDT and GDT registers
lidt [IDT_Pointer]
lgdt [GDT_Pointer]
; Initialize the interrupt controllers, and enable the
; A20 address line
Interrupt를 처리하는 PIC 컨틀롤러를 셋팅한다.
call Init_PIC
메모리 주소를 모두 사용하기 위해서 A20 을 활성화 시킨다. 그런데 왜 이게
키보드에 연결되어 있는지는 모르겠음
call Enable_A20
; Switch to protected mode!
mov ax, 0x01
lmsw ax
; Jump to 32 bit code.
; NASM probably has a way to express this using
; instruction mnemonics, but I don't know how, so I
; just copied this stuff from Linux/KTK :-)
이제 보호모드로 점프한다. setup_32를 보자
db 0x66 ; operand size override prefix
db 0xea ; jmp opcode
dd (SETUPSEG<<4) + setup_32 ; want to jump here
dw KERNEL_CS ; ...in the kernel code segment
[BITS 32]
setup_32:
지금부터 보호모드이다.
; set up data segment registers
mov ax, KERNEL_DS
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
; Create the stack for the initial kernel thread.
mov esp, KERN_STACK + 4096
; Build Boot_Info struct on stack.
; Note that we push the fields on in reverse order,
; since the stack grows downwards.
main 함수를 콜할 때 넘겨줄 파라매터를 셋팅한다. 앞에서 저장한
메모리 사이즈가 들어간다.
mov eax, [(SETUPSEG<<4)+mem_size_kbytes]
push eax ; memSizeKB
push dword 8 ; bootInfoSize
; Pass pointer to Boot_Info struct as argument to kernel
; entry point.
push esp
; Push return address to make this look like a call
; XXX - untested
push dword (SETUPSEG<<4)+.returnAddr
; Far jump into kernel
실제 main.c 의 main 함수로 점프한다.
jmp KERNEL_CS:ENTRY_POINT
.returnAddr:
; We shouldn't return here.
.here: jmp .here
[BITS 16]
; Kill the floppy motor.
; This code was shamelessly stolen from Linux.
Kill_Motor:
mov dx, 0x3f2
xor al, al
out dx, al
ret
Init_PIC:
; Initialize master and slave PIC!
mov al, ICW1
out 0x20, al ; ICW1 to master
call Delay
out 0xA0, al ; ICW1 to slave
call Delay
mov al, ICW2_MASTER
out 0x21, al ; ICW2 to master
call Delay
mov al, ICW2_SLAVE
out 0xA1, al ; ICW2 to slave
call Delay
mov al, ICW3_MASTER
out 0x21, al ; ICW3 to master
call Delay
mov al, ICW3_SLAVE
out 0xA1, al ; ICW3 to slave
call Delay
mov al, ICW4
out 0x21, al ; ICW4 to master
call Delay
out 0xA1, al ; ICW4 to slave
call Delay
mov al, 0xff ; mask all ints in slave
out 0xA1, al ; OCW1 to slave
call Delay
mov al, 0xfb ; mask all ints but 2 in master
out 0x21, al ; OCW1 to master
call Delay
ret
; Linux uses this code.
; The idea is that some systems issue port I/O instructions
; faster than the device hardware can deal with them.
Delay:
jmp .done
.done: ret
; Enable the A20 address line, so we can correctly address
; memory above 1MB.
Enable_A20:
mov al, 0xD1
out 0x64, al
call Delay
mov al, 0xDF
out 0x60, al
call Delay
ret
; ----------------------------------------------------------------------
; Setup data
; ----------------------------------------------------------------------
mem_size_kbytes: dd 0
; ----------------------------------------------------------------------
; The GDT. Creates flat 32-bit address space for the kernel
; code, data, and stack. Note that this GDT is just used
; to create an environment where we can start running 32 bit
; code. The kernel will create and manage its own GDT.
; ----------------------------------------------------------------------
GDT 와 IDT 관련은 인텔 메뉴얼을 보면 구조가 잘 설명되어 있다.
; GDT initialization stuff
NUM_GDT_ENTRIES equ 3 ; number of entries in GDT
GDT_ENTRY_SZ equ 8 ; size of a single GDT entry
align 8, db 0
GDT:
; Descriptor 0 is not used
dw 0
dw 0
dw 0
dw 0
; Descriptor 1: kernel code segment
dw 0xFFFF ; bytes 0 and 1 of segment size
dw 0x0000 ; bytes 0 and 1 of segment base address
db 0x00 ; byte 2 of segment base address
db 0x9A ; present, DPL=0, non-system, code, non-
conforming,
; readable, not accessed
db 0xCF ; granularity=page, 32 bit code, upper nibble of size
db 0x00 ; byte 3 of segment base address
; Descriptor 2: kernel data and stack segment
; NOTE: what Intel calls an "expand-up" segment
; actually means that the stack will grow DOWN,
; towards lower memory. So, we can use this descriptor
; for both data and stack references.
dw 0xFFFF ; bytes 0 and 1 of segment size
dw 0x0000 ; bytes 0 and 1 of segment base address
db 0x00 ; byte 2 of segment base address
db 0x92 ; present, DPL=0, non-system, data, expand-up,
; writable, not accessed
db 0xCF ; granularity=page, big, upper nibble of size
db 0x00 ; byte 3 of segment base address
GDT_Pointer:
dw NUM_GDT_ENTRIES*GDT_ENTRY_SZ ; limit
dd (SETUPSEG<<4) + GDT ; base address
IDT_Pointer:
dw 0
dd 00
댓글 달기