My Operating system Development Experience and understanding -Part 03
in this article we are going to implement Drivers for our operating system which is act as a layer between the Kernel and the Hardware. before reading article I like to say that I haven’t include all the codes in picture type because I got some mails about last article to include codes in zip file like what I did in 1st article so I include codes in a zip file
Drivers teach the operating system to interact with each bit of hardware. Graphics cards, sound cards, networking cards, USB peripherals, and everything else you connect to your computer relies on drivers. The operating system then uses these drivers to ensure correct operation of each device.
The way to interact with hardware has two, memory maps I / O and I/ O ports.
Memory-mapped I/O uses the same address space to address both memory and I/O devices. The memory and registers of the I/O devices are mapped to (associated with) address values. So a memory address may refer to either a portion of physical RAM, or instead to memory of the I/O device. Thus, the CPU instructions used to access the memory can also be used for accessing devices.
If the hardware uses the I / O of the memory map, you can write a specific memory address, and the hardware will be updated using new data. The frame buffer is an example and will be discussed in detail later.
For example, if the value 0x410f is written to the address 0x000b8000, the white letter A will be seen on a black background
An I/O port is a socket on a computer that a cable is plugged into. The port connects the CPU to a peripheral device via a hardware interface or to the network via a network interface.
If the hardware uses the I / O port, you must communicate with the hardware using the assembly code instructions of OUT and IN. The OUT command has two parameters: the address of the I / O port, and the data to be sent. The in order uses a single parameter, that is, the address of the I / O port, and returns data from the hardware. The I / O port can be deemed to communicate with the hardware is the same as the usage socket communication with the server. The cursor (flicker rectangle) frame buffer is an example of hardware controlled through the I / O port on the PC.
2. Frame buffer
A framebuffer (frame buffer, or sometimes frame store) is a portion of random-access memory (RAM) containing a bitmap that drives a video display. It is a memory buffer containing data representing all the pixels in a complete video frame.. The framebuffer has 80 columns and 25 rows, and the row and column indices start at 0 (so rows are labelled 0–24).
The text write console is performed by the frame buffer is completed by the I / O map of memory. The starting address of the memory mapping I / O of the frame buffer is 0x000b8000.The memory is divided into 16-bit unit, 16 bits determine characters, foreground, and background colors. The highest eight is the character’s ASCII value, bit 7–4 is the background, bit 3–0 is the foreground,
As shown below:
The first cell corresponds to the first line, the zero column on the console. Using the ASCII table, you can see A correspond to 65 or 0x41. Therefore, it is necessary to write character A with green foreground (2) and dark gray background (8) at position (0, 0), use the following assembly code instructions:
mov [0x000B8000], 0x4128
Then, the second cell corresponds to the first column of the ziping line, so its address is:
0x000B8000 + 16 = 0x000B8010
By treating address 0x000B8000 as a CHAR pointer char * fb = (char *) 0x000b8000, the write to the frame buffer can be completed in the C language. Then, write A to the position (0, 0) having a green foreground and dark gray background to:
fb = ‘A’;
fb = 0x28;
The following shows how to apply it to a function:
After that, you can use it:
The cursor of the mobile frame buffer is done by two different I / O ports. The position of the cursor is determined by 16-bit integers:
0 denotes line 0, column 0; 1 means row 0, column 1; 80 means a row, zero column, and so on. Since the location is 16 digits, the assembly code instructions are 8 bits, so it must be sent to the two laps, first send 8 bits, and then send the next 8 bits. The frame buffer has two I / O ports, one for receiving data, and the other for describing the received data.
Port 0x3d4 is a port for describing data,
The port 0x3d5 is used for the data itself.
To set the cursor in the first row column (position 80 = 0x0050), the following assembly code instructions will be used:
The OUT assembly code instruction cannot be executed directly in C. Therefore, it is best to package a assembly code in a function, which can be accessed from C via CDECL calls.
By storing this function in a file name io.s, you can easily access the OUT assembly code instruction from C from C after make a c file io.h
Driver should provide an interface to make other code in the OS and interact with Framebuffer.
The features that the interface should provide is not pair, but it is recommended to use the WRITE function with the following declaration:
int write(char *buf, unsigned int len);
Write Funcit writes the contents of the length of the buffer buffer BUF to the screen. After writing characters, the write function should automatically advance the cursor and scroll the screen when necessary.
The serial port is an interface for communicating between hardware devices, although almost on all motherboards, now it is rarely exposed to the user in the form of a DE-9 connector. Serial port is easy to use, more importantly, it can be used as logging utilities in Bochs.
If your computer supports a serial port, it usually supports multiple serial ports, but we will only use one of the ports.
This is because we will only use the serial port for logging. In addition, we only use the serial port for output instead of input.
The serial port is fully controlled through the I / O port.
Configuring the serial port
The first data that needs to be sent to the serial port is configuration data. In order for two hardware devices to communicate with each other, they must reach a consensus on several things. These things include: speed (bit or baud rate) for transmitting data (bit or baud rate) If you should use any error check (parity bit, stop bit) to indicate the number of bits (data bits)
Configure the line
Configuring the line means configuring how data is sent over the line. The serial port has an I / O port, that is, a line command port for configuration. First, the speed of sending data will be set. The serial port has an internal clock whose running frequency is 115200 Hz. Setting speed means transmitting divisions to a serial port, such as transmission 2, will result in 115200/2 = 57600 Hz speed. The divisor is 16 digits, but we can only send 8 digits at a time. Therefore, we must send a directive to inform the serial port First, we must expect the highest 8 bits, then the lowest 8 bits. This is done by sending 0x80 to the line command port. An example as follows:
You must configure the way you send data. It can also be done by sending one byte through the line command port. The 8-bit layout is as follows:
We will use most of the standard value 0x03, which means the length is 8 bits, no parity bit, 1 stop bit, and disable interrupt control. As shown in the following example, it is sent to the line command port:
Configuring Cache Area
When transmitting data through a serial port, the data is placed in the buffer whether or when receiving or transmitting data. Thus, if you send the data to the serial port, it will be buffered by sending the data through the wired network. However, if you send too much data too fast, the buffer will be full, and the data will be lost. In other words, the buffer is a FIFO queue. The FIFO queue configuration bytes are shown below:
We use 0xc7 = 11000111:
Clear reception and send FIFO queue
Use 14 bytes as the queue size
We don’t need to start Interrupts because we don’t currently do not process accepted data.
So we use 0x03 = 00000011 (RTS = 1 and DTS = 1).
Write data to the serial port
Write the data to the serial port through the data I / O port. However, before writing, send the FIFO queue must be empty (you must complete all previous writes).
If the bit 5 of the line status I / O port is equal to 1, the FIFO queue is empty. Read the contents of the I / O port through the IN assembly code instruction.
Unable to use the in assembly code instruction in C, so you must pack it (same as the OUT assembly code instruction):.
3.6 Configuring Bochs
To save the output of the first serial port, you must update the Bochs profile bochsrc.txt.
COM1 configuration indicates how Bochs handles the first serial port:
com1：enabled = 1，mode = file，dev = com1.out
The output of serial port 1 is now stored in the file com1.out.
after finishing this if you try to run OS by make run you will get error because we still not implement main function to run our functions we will disuse this in next article
link of code :
thanks for reading