Development practices of X86 operating system kernel using Delphi

Source: Internet
Author: User

----- Old Gill --------

As a rad tool on Windows, Delphi attracts many software companies to develop application-layer software. In addition to the efficiency of rad, the openness of Delphi (open source code, easy to go deep into the underlying layer) makes a lot of developers feel at ease. Delphi, as a 32-bit compiler on an excellent Windows platform, is widely used, many foreign organizations have used Delphi to develop advanced compilers, drivers, and even operating systems. I have made some attempts and feel another wide world of Delphi.

This article will show you how to use Delphi to develop the x86 operating system kernel. It aims to give a look and inspire developers to conduct more in-depth research on excellent compilers.

First, we will introduce the general framework of the image file (floppy disk image file) of a simple OS prototype in this article (interested readers can reschedule and expand it on their own ):

[Operating System Framework]:
The startup code initializes the necessary protection mode, loads the OS core code, initializes the segment registers, and directly jumps to the OS core code for execution.
The startup code is compiled by assembly and NASM, And the OS core code is implemented by Delphi.

Step 1: Generate startup code
The main function of starting code is to build gdt (including code segments and data segments, flat memory settings), read the kernel code to 0x8000, switch to the protection mode, and jump to the kernel. The content is as follows:

[Bits 16]
[Org 0x7c00]

JMP bootbegin

; Gdt data
Gdtbegin:

; Empty Descriptor

Dd 0

Dd 0

Codesel equ $-gdtbegin; code segment Selection Sub-

; Code segment descriptor

DW 0 xFFFF

DW 0

DW 0x9a00

DW 0x00cf

Datasel equ $-gdtbegin; Data Segment Selection Sub-

; Data segment descriptor

DW 0 xFFFF

DW 0x0000

DW 0x9200

DW 0x00cf

Gdtend:

Gdtinfo:

DW gdtend-gdtbegin-1; gdt size

Dd gdtbegin; gdt address

Bootbegin:

MoV ax, CS

MoV ds, ax

 

; Read the kernel from the second sector to 0000: 0x8000 (ES: BX) in the memory

; (Read 17 sectors, which can be expanded by the reader)

Readkernel:

MoV ax, 0x0000

MoV es, ax

MoV BX, 0x8000

MoV ah, 2

MoV DL, 0

MoV CH, 0

MoV Cl, 2

MoV Al, 17

INT 13 H

JC readkernel

 

 

; Guanzhong disconnection

CLI

; Load gdt

Lgdt [gdtinfo]

 

; Enter the protection mode

MoV eax, Cr0

Or eax, 1

MoV Cr0, eax

 

; Jump into the 32-bit code segment

JMP codesel: code32begin

[Bits 32]

Code32begin:

; Set ds, es, SS, FS, GS

MoV ax, datasel

MoV ds, ax

MoV es, ax

MoV SS, ax

MoV FS, ax

MoV Gs, ax

MoV ESP, 0x30000; initial stack settings

 

; Jump to the kernel

JMP codesel: 0x8000

;---------------------------------------------------------------------------

Times 510-($-$) db 0

; Boot disk flag

DW 0xaa55

Use NASM to compile a COM file and write the first sector (0-0x01ff) of the image file ). complete the startup code settings (note: the simplest way to generate the original image file is to use ultraedit to generate a binary file with the size of 0x167fff. You can also use the ultraedithex edit function to enable code writing ).

Step 2: develop core code

The following describes how to use Delphi to develop core OS code.

First, let's take a look at the structure of the PE code segment generated by Delphi. For projects that do not explicitly reference any system unit, Delphi will add system to the front of the code segment by default. PAS and sysinit. the PAS two Delphi core runtime libraries RTL. RTL is our own unit, and finally the begin in program... To simplify the cumbersome operations of loading kernel code from a PE file, we can use only the code segment and run it after the sysinit Unit (before the OS core code) add a tag to the end of the program code. The code between the two tags is that we want the OS code. You can change your mind or use multiple segments, you only need to conveniently load the kernel from the PE.

To simplify development, this article involves several key points for compiling the operating system code using Delphi:

1. Do not rely on RTL and do not call any RTL functions of Delphi.
2. Define data in the Code (use embedded assembly), use only code segments, and use relative
Addressing ensures that the code can be loaded to any location in the memory for execution.
3. Because it is the OS kernel, the memory can be used at will after planning, and you do not need to apply for it.

OK. Now open Delphi, create an empty project (no reference to any unit), and add an empty unit kernel. PAS (OS Kernel unit), then add a process kernelbegin to the unit as the kernel entry process, and mark the kernel start and end at the unit start and project end, first, implement simple kernel operations. Call the showtest process to display two characters 'OS' on the screen and then enter an endless loop. The Code content is as follows:

Program oskernel;

Uses

Kernel in 'kernel. pa ';

Begin

// The explicitly called code will be compiled into the EXE by Delphi, so useful code should be called.

Kernelbeginflag;

// Kernel end mark

ASM

Db'kernelend'

End;

End.

 

Unit kernel;

Interface

// Kernel start marking process

Procedure kernelbeginflag;

// Kernel entry

Procedure kernelbegin; stdcall;

// Display characters: 'OS' is displayed in the 11th rows and 1st columns of the screen'

Procedure showtest; stdcall;

Implementation

 

// Start marking process of the kernel,

// Adjust the unit reference order when expanding the number of units to ensure that the process is compiled in the header of the kernel code (you can view it through Delphi disassembly)

Procedure kernelbeginflag;

Begin

ASM

Db'kernelbegin'

End;

Kernelbegin;

End;

 

Procedure kernelbegin; stdcall;

Begin

// Start kernel operations

Showtest;

End;

Procedure showtest; stdcall;

VaR P: pchar;

Begin

P: = pchar ($ b8000 + (80*10 + 0) * 2); // calculate the video address corresponding to the row and column

P [0]: = 'O ';

P [1]: = # $ 0C; // display the black-bottom red letter of the attribute

P [2]: ='s ';

P [3]: = # $ 0C;

 

While true do;

End;

End.

 

Compile and generate oskernel.exe. Now you need a tool to capture the kernel code to the beginning of the second sector of the image file. The following program implements this function (also written in Delphi ):

Program writeostoimg;

Uses

Dialogs, classes, sysutils;

VaR F1, F2: tfilestream;

B: Char;

P: pointer;

Begin

F1: = nil;

F2: = nil;

Try

Try

F1: = tfilestream.create('oskernel.exe ', fmopenread );

F2: = tfilestream. Create ('myos. IMG ', fmopenwrite );

F2.position: = $200;

While true do

Begin

F1.read (B, 1 );

If B <> 'K' then continue;

F1.read (B, 1 );

If B <> 'E' then continue;

F1.read (B, 1 );

If B <> 'R' then continue;

F1.read (B, 1 );

If B <> 'n' then continue;

F1.read (B, 1 );

If B <> 'E' then continue;

F1.read (B, 1 );

If B <> 'l' then continue;

F1.read (B, 1 );

If B <> 'B' then continue;

F1.read (B, 1 );

If B <> 'E' then continue;

F1.read (B, 1 );

If B <> 'G' then continue;

F1.read (B, 1 );

If B <> 'I 'then continue;

F1.read (B, 1 );

If B <> 'n' then continue;

Break;

End;

// Copy the kernel. For the sake of simplicity, only 10 k is copied.

Getmem (p, 1024*10 );

Try

F1.read (P ^, 1024*10 );

F2.write (P ^, 1024*10 );

Finally

Freemem (p, 1024*10 );

End;

Showmessage ('kernel writing is complete! ');

Finally

F1.free;

F2.free;

End;

Except

Showmessage ('kernel writing error! ');

End;

End.

Slave to write the kernel. You can use virtualpc (because the running result of virtualpc is closer to the actual machine) to run our floppy disk image file myos. IMG. The running result is as follows:

 

OK. Although it is only two simple characters, it is of great significance. We successfully implemented the OS jump to the kernel developed by Delphi, which means that we can use Delphi for efficient and convenient OS development, it is convenient to perform independent testing of operating modules without the operating system in Delphi. modules with core operations such as privileged/direct write memory need to be debugged under bochs, due to space limitations, we will not introduce the bochs debugging method here. If you are interested, you can consult relevant information on the Internet.

To inspire readers to expand their ideas, the following describes how to access the data defined in the Code segment to ensure that the code can run anywhere in the memory, such as in the kernel. the following code adds the dispstr (the string ends with/0) process to display a string in a specific column in PAS:

Procedure dispstr (rowid, colid: integer; P: pchar); stdcall;

VaR H: pchar;

I: integer;

Begin

H: = pchar ($ b8000 + (80 * rowid + colid) * 2 );

I: = 0;

While true do

Begin

If P [I] = #0 Then break;

H [I * 2]: = P [I];

H [I * 2 + 1]: = # $ 0C;

INC (I );

End;

End;

The Code is as follows:

Procedure kernelbegin; stdcall;

Label dispdat1, kbegin;

VaR P1: pchar;

Begin

// Obtain the first address of the string to be displayed.

ASM

Push ESI

Call @ bb

@ BB:

// Obtain the actual running address of the service during running to ESI to ensure that the code can run anywhere in the memory.

Pop ESI

 

// Calculate the address of dispdat1 during actual running.

MoV EBX, offset dispdat1

Sub EBX, offset @ bb

Add EBX, ESI

MoV P1, EBX

 

Pop ESI

JMP kbegin

 

Dispdat1: DB 'my OS 2006 is loading... ', 0 // string to be displayed

Kbegin:

End;

Dispstr (11,22, P1 );

While true do;

End;

Note the usage of the Call Command. Use the call command principle (press the next command address to stack and jump to the destination address) to allow the call command to directly call the next command, the current address can be retrieved from the stack at the next instruction, so that the runtime addresses around the stack can be obtained by using the offset address difference, in this way, the compiled module achieves the goal of normal operation without the need to relocate untitled addresses.

In particular, privileged commands can be directly used using the Embedded Assembly Technology of Delphi, and can be compiled. x86 data structures use the structure definition of Delphi to replace the direct byte definition of assembly, this greatly facilitates the organization of the kernel.

So far, readers should have a basic perceptual knowledge about the use of Delphi for x86 OS development. Interested readers can start to expand the OS kernel from kernelbegin, for example, you can set enable pagination, enable interrupt, and perform simple process scheduling control. The OS technology is the basis of software technology, and you can use a convenient development tool like Delphi for hands-on OS technology practices, I believe it is very attractive for a wide range of software enthusiasts and convenient for developers who have been working on Windows platforms for a long time. Aside from the cumbersome operating system development in Linux, the world is much more open. If you are interested in OS technology, you can try it yourself right away. What are you waiting!

......... Old Gill ...... under the chrysanthemum dashboard. You can see Nanshan... 2007. 02 ......

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.