8000 [07-multiboot] Create multiboot information parser demo from 02-printf · havensjg/osdev-demos@ca8fa22 · GitHub
[go: up one dir, main page]

Skip to content

Commit ca8fa22

Browse files
committed
[07-multiboot] Create multiboot information parser demo from 02-printf
1 parent 0b6b94f commit ca8fa22

File tree

16 files changed

+771
-0
lines changed

16 files changed

+771
-0
lines changed

07-multiboot/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
build/

07-multiboot/CMakeLists.txt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
cmake_minimum_required(VERSION 3.17.0)
2+
3+
# prevent cmake from making test executables??
4+
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
5+
6+
# set up i686-elf cross-compiler tools
7+
include(toolchain-i686-elf.cmake)
8+
9+
project(OSDEV)
10+
11+
# enable assembly
12+
enable_language(ASM)
13+
14+
# check that grub is installed
15+
find_program(GRUB_EXECUTABLE grub-mkrescue REQUIRED)
16+
17+
# directory/ies containing header files
18+
include_directories(include)
19+
20+
# set up iso file structure
21+
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/isodir)
22+
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/isodir/boot)
23+
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/isodir/boot/grub)
24+
25+
# iso file
26+
add_custom_target(livecd
27+
COMMAND ${GRUB_EXECUTABLE} -o ${CMAKE_CURRENT_BINARY_DIR}/myos.iso ${CMAKE_CURRENT_BINARY_DIR}/isodir
28+
VERBATIM
29+
)
30+
31+
# grub.cfg into isodir
32+
add_dependencies(livecd grub_cfg)
33+
add_custom_target(grub_cfg
34+
COMMAND ${CMAKE_COMMAND} -E copy
35+
${CMAKE_SOURCE_DIR}/src/grub.cfg
36+
${CMAKE_CURRENT_BINARY_DIR}/isodir/boot/grub/grub.cfg
37< 6D40 span class="diff-text-marker">+
)
38+
39+
# myos.bin into isodir
40+
add_dependencies(livecd myos_bin)
41+
add_custom_target(myos_bin
42+
COMMAND ${CMAKE_COMMAND} -E copy
43+
${CMAKE_CURRENT_BINARY_DIR}/myos.bin
44+
${CMAKE_CURRENT_BINARY_DIR}/isodir/boot/myos.bin
45+
DEPENDS myos.bin
46+
)
47+
48+
# myos.bin
49+
file(GLOB C_SOURCES
50+
"include/*.h"
51+
"src/*.c"
52+
)
53+
set_source_files_properties(${C_SOURCES} PROPERTIES COMPILE_OPTIONS "-std=gnu99;-ffreestanding;-O2;-Wall;-Wextra")
54+
55+
file (GLOB ASM_SOURCES
56+
"src/*.s"
57+
)
58+
59+
add_executable(myos.bin
60+
${C_SOURCES}
61+
${ASM_SOURCES}
62+
)
63+
set_target_properties(myos.bin PROPERTIES LINK_DEPENDS ${CMAKE_SOURCE_DIR}/src/linker.ld)
64+
target_link_libraries(myos.bin gcc)
65+
target_link_options(myos.bin PUBLIC -ffreestanding -O2 -nostdlib -T ${CMAKE_SOURCE_DIR}/src/linker.ld)

07-multiboot/include/io.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <stdint.h>
2+
3+
/* x86 outb instruction */
4+
static inline void outb(uint16_t port, uint8_t val)
5+
{
6+
asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
7+
/* There's an outb %al, $imm8 encoding, for compile-time constant port numbers that fit in 8b. (N constraint).
8+
* Wider immediate constants would be truncated at assemble-time (e.g. "i" constraint).
9+
* The outb %al, %dx encoding is the only option for all other cases.
10+
* %1 expands to %dx because port is a uint16_t. %w1 could be used if we had the port number a wider C type */
11+
}
12+
13+
/* x86 inb instruction */
14+
static inline uint8_t inb(uint16_t port)
15+
{
16+
uint8_t ret;
17+
asm volatile ( "inb %1, %0"
18+
: "=a"(ret)
19+
: "Nd"(port) );
20+
return ret;
21+
}
22+
23+
/* x86 outw instruction */
24+
static inline void outw(uint16_t port, uint16_t val)
25+
{
26+
asm volatile ( "outw %0, %1" : : "a"(val), "Nd"(port) );
27+
}
28+
29+
/* x86 inw instruction */
30+
static inline uint16_t inw(uint16_t port)
31+
{
32+
uint16_t ret;
33+
asm volatile ( "inw %1, %0"
34+
: "=a"(ret)
35+
: "Nd"(port) );
36+
return ret;
37+
}
38+
39+
/* x86 outl instruction */
40+
static inline void outl(uint16_t port, uint32_t val)
41+
{
42+
asm volatile ( "outl %0, %1" : : "a"(val), "Nd"(port) );
43+
}
44+
45+
/* x86 inl instruction */
46+
static inline uint32_t inl(uint16_t port)
47+
{
48+
uint32_t ret;
49+
asm volatile ( "inl %1, %0"
50+
: "=a"(ret)
51+
: "Nd"(port) );
52+
return ret;
53+
}

07-multiboot/include/stdio.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#pragma once
2+
3+
#define EOF (-1)
4+
5+
int printf(const char* __restrict, ...);
6+
int putchar(int);

07-multiboot/include/string.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#pragma once
2+
3+
#include <stddef.h>
4+
5+
void* memmove(void* dstptr, const void* srcptr, size_t size);
6+
7+
size_t strlen(const char *str);

07-multiboot/include/terminal.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#pragma once
2+
3+
#include <stddef.h>
4+
#include <stdint.h>
5+
6+
/* Initialize the terminal output */
7+
void terminal_initialize(void);
8+
9+
/* Scroll the terminal by one line */
10+
void terminal_scroll(void);
11+
12+
/* Set the color of the next characters to be printed */
13+
void terminal_set_color(uint8_t color);
14+
15+
/* Set the position of the cursor */
16+
void terminal_set_cursor(unsigned int x, unsigned int y);
17+
18+
/* Print one character and update cursor */
19+
void terminal_putchar(char c);
20+
21+
/* Put the character at the given position with the given color */
22+
void terminal_putentryat(char c, uint8_t color, size_t x, size_t y);
23+
24+
/* Write a string of a given size */
25+
void terminal_write(const char* data, size_t size);
26+
27+
/* Write a null-terminated string */
28+
void terminal_writestring(const char* data);

07-multiboot/include/vga.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
/* Dimensions of the text mode screen*/
6+
#define VGA_WIDTH 80
7+
#define VGA_HEIGHT 25
8+
9+
/* VGA IO Ports */
10+
#define VGA_CRTC_INDEX 0x3D4
11+
#define VGA_CRTC_DATA 0x3D5
12+
13+
/* CRTC register indices */
14+
#define VGA_CRTC_REG_CURSOR_POS_HIGH 0x0E
15+
#define VGA_CRTC_REG_CURSOR_POS_LOW 0x0F
16+
17+
/* Hardware text mode color constants. */
18+
enum vga_color {
19+
VGA_COLOR_BLACK = 0,
20+
VGA_COLOR_BLUE = 1,
21+
VGA_COLOR_GREEN = 2,
22+
VGA_COLOR_CYAN = 3,
23+
VGA_COLOR_RED = 4,
24+
VGA_COLOR_MAGENTA = 5,
25+
VGA_COLOR_BROWN = 6,
26+
VGA_COLOR_LIGHT_GREY = 7,
27+
VGA_COLOR_DARK_GREY = 8,
28+
VGA_COLOR_LIGHT_BLUE = 9,
29+
VGA_COLOR_LIGHT_GREEN = 10,
30+
VGA_COLOR_LIGHT_CYAN = 11,
31+
VGA_COLOR_LIGHT_RED = 12,
32+
VGA_COLOR_LIGHT_MAGENTA = 13,
33+
VGA_COLOR_LIGHT_BROWN = 14,
34+
VGA_COLOR_WHITE = 15,
35+
};
36+
37+
/* Create a VGA text-mode attribute byte */
38+
static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
39+
{
40+
return fg | bg << 4;
41+
}
42+
43+
/* Create a VGA text-mode character-attribute pair */
44+
static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
45+
{
46+
return (uint16_t) uc | (uint16_t) color << 8;
47+
}

07-multiboot/readme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Adapted from 02-printf
2+
3+
The GRUB bootloader provides information to the kernel in a structure whose pointer is passed to the kernel entry point in the EBX register. This example will read and parse that structure.
4+
5+
[Multiboot specification](https://www.gnu.org/software/grub/manual/multiboot/multiboot.html)

07-multiboot/src/boot.s

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/* Declare constants for the multiboot header. */
2+
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
3+
.set MEMINFO, 1<<1 /* provide memory map */
4+
.set FLAGS, ALIGN | MEMINFO /* this is the Multiboot 'flag' field */
5+
.set MAGIC, 0x1BADB002 /* 'magic number' lets bootloader find the header */
6+
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot */
7+
8+
/*
9+
Declare a multiboot header that marks the program as a kernel. These are magic
10+
values that are documented in the multiboot standard. The bootloader will
11+
search for this signature in the first 8 KiB of the kernel file, aligned at a
12+
32-bit boundary. The signature is in its own section so the header can be
13+
forced to be within the first 8 KiB of the kernel file.
14+
*/
15+
.section .multiboot
16+
.align 4
17+
.long MAGIC
18+
.long FLAGS
19+
.long CHECKSUM
20+
21+
/*
22+
The multiboot standard does not define the value of the stack pointer register
23+
(esp) and it is up to the kernel to provide a stack. This allocates room for a
24+
small stack by creating a symbol at the bottom of it, then allocating 16384
25+
bytes for it, and finally creating a symbol at the top. The stack grows
26+
downwards on x86. The stack is in its own section so it can be marked nobits,
27+
which means the kernel file is smaller because it does not contain an
28+
uninitialized stack. The stack on x86 must be 16-byte aligned according to the
29+
System V ABI standard and de-facto extensions. The compiler will assume the
30+
stack is properly aligned and failure to align the stack will result in
31+
undefined behavior.
32+
*/
33+
.section .bss
34+
.align 16
35+
stack_bottom:
36+
.skip 16384 # 16 KiB
37+
stack_top:
38+
39+
/*
40+
The linker script specifies _start as the entry point to the kernel and the
41+
bootloader will jump to this position once the kernel has been loaded. It
42+
doesn't make sense to return from this function as the bootloader is gone.
43+
*/
44+
.section .text
45+
.global _start
46+
.type _start, @function
47+
_start:
48+
/*
49+
The bootloader has loaded us into 32-bit protected mode on a x86
50+
machine. Interrupts are disabled. Paging is disabled. The processor
51+
state is as defined in the multiboot standard. The kernel has full
52+
control of the CPU. The kernel can only make use of hardware features
53+
and any code it provides as part of itself. There's no printf
54+
function, unless the kernel provides its own <stdio.h> header and a
55+
printf implementation. There are no security restrictions, no
56+
safeguards, no debugging mechanisms, only what the kernel provides
57+
itself. It has absolute and complete power over the
58+
machine.
59+
*/
60+
61+
/*
62+
To set up a stack, we set the esp register to point to the top of the
63+
stack (as it grows downwards on x86 systems). This is necessarily done
64+
in assembly as languages such as C cannot function without a stack.
65+
*/
66+
mov $stack_top, %esp
67+
68+
/*
69+
This is a good place to initialize crucial processor state before the
70+
high-level kernel is entered. It's best to minimize the early
71+
environment where crucial features are offline. Note that the
72+
processor is not fully initialized yet: Features such as floating
73+
point instructions and instruction set extensions are not initialized
74+
yet. The GDT should be loaded here. Paging should be enabled here.
75+
C++ features such as global constructors and exceptions will require
76+
runtime support to work as well.
77+
*/
78+
79+
/*
80+
Enter the high-level kernel. The ABI requires the stack is 16-byte
81+
aligned at the time of the call instruction (which afterwards pushes
82+
the return pointer of size 4 bytes). The stack was originally 16-byte
83+
aligned above and we've pushed a multiple of 16 bytes to the
84+
stack since (pushed 0 bytes so far), so the alignment has thus been
85+
preserved and the call is well defined.
86+
*/
87+
call kernel_main
88+
89+
/*
90+
If the system has nothing more to do, put the computer into an
91+
infinite loop. To do that:
92+
1) Disable interrupts with cli (clear interrupt enable in eflags).
93+
They are already disabled by the bootloader, so this is not needed.
94+
Mind that you might later enable interrupts and return from
95+
kernel_main (which is sort of nonsensical to do).
96+
2) Wait for the next interrupt to arrive with hlt (halt instruction).
97+
Since they are disabled, this will lock up the computer.
98+
3) Jump to the hlt instruction if it ever wakes up due to a
99+
non-maskable interrupt occurring or due to system management mode.
100+
*/
101+
cli
102+
1: hlt
103+
jmp 1b
104+
105+
/*
106+
Set the size of the _start symbol to the current location '.' minus its start.
107+
This is useful when debugging or when you implement call tracing.
108+
*/
109+
.size _start, . - _start

07-multiboot/src/grub.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
menuentry "myos" {
2+
multiboot /boot/myos.bin
3+
}

0 commit comments

Comments
 (0)
0