;; 02.Kernel64/EntryPoint.s
[BITS 64]
Section .text
extern Main ; Main function in 02.Kernel64/Main.c
START:
mov ax, 0x10 ; IA-32e mode's data segment; def is in 32 bit EntryPoint.s
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; address from 0x600000~0x6FFFFF (1MiB) is for stack
mov ss, ax
mov rsp, 0x6FFFF8
mov rbp, 0x6FFFF8
; Unlike 32 bit EntryPoint.s, here I show there is another way to execute
; code in C language
call Main
jmp $ ; this instruction will not be executed // 02.Kernel64/Main.c
// Types.h is exactly same as one in 02.Kernel32. You can just copy it
// to 02.Kernel64/Source
#include "Types.h"
void kPrintString(int iX, int iY, const char *pcString);
void Main(void) {
kPrintString(0, 10, "Switch To IA-32e Mode Success~!!");
kPrintString(0, 11, "IA-32e C Language Kernel Start............. [PASS]");
}
// write string to specific addr which is used for text mode, so you can
// see string in screen.
// iX: row where string will be
// possible range: [0~24]
// iY: column where string will be
// possible range: [0~79]
// string: string to write in screen
//
// if string overflows iY, it wll be written to next line
// There is no protection for memory overflow. This means if your string
// overflows iX, the string can be written to Kernel area in worst case
void kPrintString(int iX, int iY, const char *pcString) {
CHARACTER *pstScreen = (CHARACTER *) 0xB8000;
int i;
pstScreen += iY * 80 + iX;
for (i = 0; pcString[i] != 0; i++) {
pstScreen[i].bCharacter = pcString[i];
}
}/*
* 02.Kernel/binary_amd64.x
*/
OUTPUT_FORMAT("binary")
OUTPUT_ARCH(i386:x86-64)
SECTIONS {
/* long mode code resides at 0x200000
* Instead of concatenating EntryPoint.bin with Kernel.bin, EntryPoint is
* also involved in the linking process
*/
.text 0x200000 : {
/* text section of Main file comes first in file*/
EntryPoint.o(.text)
Main.o(.text)
/* text section of other files comes after main in the order of input */
*(.text)
}
. = ALIGN(512);
/* as .rodata data comes here, operand of instruction that references to a
* data in .rodata is adjusted
*/
.rodata : {
*(.rodata)
/* add padding to the end so .rodata is aligned to multiply of 512 */
}
/* discard all other sections in input files. If this is not specified,
* ld adds the sections somewhere in the program although instruction to
* add the sections is not in the script
*/
/DISCARD/ : {
*(*)
}
}
-
In
01.Kernel32, binary was made byconcatenatingEntryPoint.bin and Kernel32_C.bin. In memory layout, EntryPoint.bin is at 0x10000 and Kerne32_c.bin is at 0x10200. EntryPoint.binexactly jumpto 0x10200 to execute C code. However, In 02.Kernel64, I show different way to make 64 bit kernel. -
In
02.Kernel64, EntryPoint.s is supposed to be at 0x200000 (2MB) in memory layout, the codecallsMain function in C code instead of jumping to specific address. EntryPoint.s is compiled intoELFobject file and all object files are passed to linker script so it resolves the address problem. All we need is to make sure that the 64 bit EntryPoint.s is loaded at 0x200000
- They are almost the same as linker script in 01.Kernel32. The only
difference is that OUTPUT_ARCH is changed for
x86_64, andEntryPoint.ois the first line in.textsection, and .text memory address