mirror of
https://github.com/cowmonk/cowos.git
synced 2025-10-27 14:33:27 +00:00
Branch sync and push, reformated and made the OS look more "official"
This commit is contained in:
parent
13389f9617
commit
59e39d9842
9 changed files with 270 additions and 0 deletions
29
README.md
29
README.md
|
|
@ -1,2 +1,31 @@
|
||||||
# cowos
|
# cowos
|
||||||
Custom OS from scratch in C
|
Custom OS from scratch in C
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
This only supports 32bit for now, please DO NOT compile with 64bit or it'll fail to boot
|
||||||
|
|
||||||
|
## compilation of any component
|
||||||
|
You are required to get your own cross C compiler. This is because normal C compilers for your Linux distro (assuming that you are on Linux) will optimize against your own libs and other things. This OS doesn't exist yet, so this is a big no no in OS development. Another thing is that you want to compile for 32 bit, so you'll need to cross compile anyways...
|
||||||
|
|
||||||
|
### general c files
|
||||||
|
```bash
|
||||||
|
i386-elf-gcc -c kernel.c -o kernel.o -std=c99 -ffreestanding -O2 -Wall -Wextra # i386 is the 32 bit version of x86
|
||||||
|
# also please compile with the -Iinclude flag to include the libraries like string.h in the arch
|
||||||
|
```
|
||||||
|
|
||||||
|
### "compiling" the "boot stub"
|
||||||
|
```bash
|
||||||
|
i386-elf-as boot.s -o boot.o
|
||||||
|
```
|
||||||
|
|
||||||
|
### linking the "compiled" boot stub w/compiled kernel img
|
||||||
|
```
|
||||||
|
i386-elf-gcc -T linker.ld -o cowos.bin -ffreestanding -O2 -nostdlib boot.o kernel.o
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting it bootable
|
||||||
|
You'll need grub and mtools. First move the compiled cowos.bin to isodir/boot. Then run the following command:
|
||||||
|
```bash
|
||||||
|
grub-mkrescue isodir/ -o cowos.iso
|
||||||
|
```
|
||||||
|
Now you can enjoy running this in qemu lol.
|
||||||
|
|
|
||||||
3
isodir/boot/grub/grub.cfg
Normal file
3
isodir/boot/grub/grub.cfg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
menuentry "cowos" {
|
||||||
|
multiboot /boot/kernel.elf
|
||||||
|
}
|
||||||
72
kernel/arch/i386/boot.s
Normal file
72
kernel/arch/i386/boot.s
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
.set ALIGN, 1<<0 /* align loaded modules on page boundaries */
|
||||||
|
.set MEMINFO, 1<<1 /* provide memory map */
|
||||||
|
.set FLAGS, ALIGN | MEMINFO /* Multiboot flag */
|
||||||
|
.set MAGIC, 0x1BADB002 /* Magic number lets bootloader find the header */
|
||||||
|
.set CHECKSUM, -(MAGIC + FLAGS) /* checksum of above, to prove we are multiboot (sanity check I think) */
|
||||||
|
|
||||||
|
/* so this basically declares the multiboot header that defines this program as a kernel,
|
||||||
|
and the following values are in the multiboot standard. The bootloader will look for the
|
||||||
|
first 8KiB of the kernel file, aligned with the 32-bit boundary, this means that it won't
|
||||||
|
work with 64bit until I keep on learning or I create my own bootloader (without multiboot)
|
||||||
|
*/
|
||||||
|
.section .multiboot
|
||||||
|
.align 4
|
||||||
|
.long MAGIC
|
||||||
|
.long FLAGS
|
||||||
|
.long CHECKSUM
|
||||||
|
|
||||||
|
/* This is where my knowledge is not high enough but here is the summary:
|
||||||
|
- esp is NOT in the multiboot standard so the kernel has to provide it.
|
||||||
|
this basically means that it doesn't define the value of the stack register
|
||||||
|
(whatever that means)
|
||||||
|
- This allocates some room for a stack by creating a symbol at the bottom of it
|
||||||
|
then allocate 16 KiB and then creating a symbol on top.
|
||||||
|
- The stack grows downwards on x86.
|
||||||
|
|
||||||
|
And many more, apparently it's re-aligned to System-V ABI standard as well? Not sure, but hopefully I can
|
||||||
|
continue learning
|
||||||
|
*/
|
||||||
|
.section .bss
|
||||||
|
.align 16
|
||||||
|
stack_bottom:
|
||||||
|
.skip 16384 # 16 KiB
|
||||||
|
stack_top:
|
||||||
|
|
||||||
|
/* linker specifies a _start as the entry point to the kernel and the bootloader will jump to the position
|
||||||
|
however it doesn't make any sense to return to this after the bootloader is gone
|
||||||
|
*/
|
||||||
|
.section .text
|
||||||
|
.global _start
|
||||||
|
.type _start, @function
|
||||||
|
_start:
|
||||||
|
/* We are now in... no printf and other things, kernel has FULL CONTROL of the cpu. No security also lol */
|
||||||
|
|
||||||
|
/* To set up a stack, this sets the esp to register to the point of the stack because it grows downwards on
|
||||||
|
on x86 systems. this is done in assembly because languages like C can't function without a stack */
|
||||||
|
mov $stack_top, %esp
|
||||||
|
|
||||||
|
/* so we need to initialize some critical processor states before the high-level kernel is entered.
|
||||||
|
interestingly a lot of things are done at the boot level, we should load GDT, enable paging, and add runtime
|
||||||
|
support (for C++). Crazy!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* time to enter the kernel,
|
||||||
|
according to the guide, this is a well defined call as the stack was originally 16-byte aligned, we pushed a
|
||||||
|
multiple of 16-bytes to the stack (since 0 bytes were pushed so far), so alignment has been perserved.
|
||||||
|
*/
|
||||||
|
call kernel_main
|
||||||
|
|
||||||
|
/* If there is nothing else to do, the computer will be in an infinite loop
|
||||||
|
- Disable interrupts with cli (they wil be disabled by the bootloader)
|
||||||
|
- Wait for next interrupt to arrive with halt instruction (hlt)
|
||||||
|
- Jump to hlt instruction if it ever wakes up due to a non-maskable
|
||||||
|
interrupt occuring or due to system management mode.
|
||||||
|
*/
|
||||||
|
cli
|
||||||
|
1: hlt
|
||||||
|
jmp 1b
|
||||||
|
|
||||||
|
/* set the size of _start symbol to the current location minus its start.
|
||||||
|
Useful for debugging or if I implement call tracing
|
||||||
|
*/
|
||||||
|
.size _start, . - _start
|
||||||
25
kernel/arch/i386/linker.ld
Normal file
25
kernel/arch/i386/linker.ld
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
ENTRY(_start) /* Entry point symbol */
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
/* Load address in memory: 2MB for kernel */
|
||||||
|
. = 2M;
|
||||||
|
|
||||||
|
/* Multiboot header must be in the first 8KB of the file and 32-bit aligned */
|
||||||
|
.text BLOCK(4K) : ALIGN(4K) {
|
||||||
|
*(.multiboot)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata BLOCK(4K) : ALIGN(4K) {
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data BLOCK(4K) : ALIGN(4K) {
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss BLOCK(4K) : ALIGN(4K) {
|
||||||
|
*(COMMON)
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
}
|
||||||
61
kernel/drivers/video/vga.c
Normal file
61
kernel/drivers/video/vga.c
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "../../include/video/vga.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
size_t term_row;
|
||||||
|
size_t term_col;
|
||||||
|
uint8_t term_color;
|
||||||
|
uint16_t* term_buf = (uint16_t*)VGA_MEMORY;
|
||||||
|
|
||||||
|
void
|
||||||
|
term_init(void)
|
||||||
|
{
|
||||||
|
term_row = 0;
|
||||||
|
term_col = 0;
|
||||||
|
term_color = vga_entry_color(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
||||||
|
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
||||||
|
const size_t index = y * VGA_WIDTH + x;
|
||||||
|
term_buf[index] = vga_entry(' ', term_color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_setcolor(uint8_t color)
|
||||||
|
{
|
||||||
|
term_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_putentryat(char c, uint8_t color, size_t x, size_t y)
|
||||||
|
{
|
||||||
|
const size_t index = y * VGA_HEIGHT + x;
|
||||||
|
term_buf[index] = vga_entry(c, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_putchar(char c)
|
||||||
|
{
|
||||||
|
term_putentryat(c, term_color, term_row);
|
||||||
|
if (++term_col == VGA_WIDTH) {
|
||||||
|
term_col = 0;
|
||||||
|
if (++term_row == VGA_HEIGHT) {
|
||||||
|
term_row = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_write(const char* data, size_t size)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
term_putchar(data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
term_writestr(const char* data)
|
||||||
|
{
|
||||||
|
term_write(data, strlen(data));
|
||||||
|
}
|
||||||
51
kernel/include/drivers/video/vga.h
Normal file
51
kernel/include/drivers/video/vga.h
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef VGA_H
|
||||||
|
#define VGA_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* hardware text mode const */
|
||||||
|
enum vga_color {
|
||||||
|
VGA_COLOR_BLACK = 0,
|
||||||
|
VGA_COLOR_BLUE = 1,
|
||||||
|
VGA_COLOR_GREEN = 2,
|
||||||
|
VGA_COLOR_CYAN = 3,
|
||||||
|
VGA_COLOR_RED = 4,
|
||||||
|
VGA_COLOR_MAGENTA = 5,
|
||||||
|
VGA_COLOR_BROWN = 6,
|
||||||
|
VGA_COLOR_LIGHT_GREY = 7,
|
||||||
|
VGA_COLOR_DARK_GREY = 8,
|
||||||
|
VGA_COLOR_LIGHT_BLUE = 9,
|
||||||
|
VGA_COLOR_LIGHT_GREEN = 10,
|
||||||
|
VGA_COLOR_LIGHT_CYAN = 11,
|
||||||
|
VGA_COLOR_LIGHT_RED = 12,
|
||||||
|
VGA_COLOR_LIGHT_MAGENTA = 13,
|
||||||
|
VGA_COLOR_LIGHT_BROWN = 14,
|
||||||
|
VGA_COLOR_WHITE = 15,
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t
|
||||||
|
vga_entry_color(enum vga_color fg, enum vga_color bg)
|
||||||
|
{
|
||||||
|
return fg | bg << 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t
|
||||||
|
vga_entry(unsigned char uc, uint8_t color)
|
||||||
|
{
|
||||||
|
return (uint16_t) uc | (uint16_t) color << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* using mode 3 of VGA 80x25 */
|
||||||
|
#define VGA_WIDTH 80
|
||||||
|
#define VGA_HEIGHT 25
|
||||||
|
#define VGA_MEMORY 0xB8000 /* VGA memory location */
|
||||||
|
|
||||||
|
void term init(void);
|
||||||
|
void term_setcolor(uint8_t color);
|
||||||
|
void term_putentryat(char c, uint8_t color, size_t x, size_t y);
|
||||||
|
void term_putchar(char c);
|
||||||
|
void term_write(const char* data, size_t size);
|
||||||
|
void term_writestr(const char* data);
|
||||||
|
|
||||||
|
#endif #VGA_H
|
||||||
8
kernel/include/lib/string.h
Normal file
8
kernel/include/lib/string.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef STRING_H
|
||||||
|
#define STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
size_t strlen(const char* str);
|
||||||
|
|
||||||
|
#endif // STRING_H
|
||||||
10
kernel/init/kernel.c
Normal file
10
kernel/init/kernel.c
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include "../include/drivers/video/vga.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
kernel_main(void)
|
||||||
|
{
|
||||||
|
term_init();
|
||||||
|
|
||||||
|
term_writestr("Hello World!\n");
|
||||||
|
}
|
||||||
11
kernel/lib/string.c
Normal file
11
kernel/lib/string.c
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include "../include/lib/string.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
size_t
|
||||||
|
strlen(const char* str)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
while (str[len]) len++;
|
||||||
|
return len;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue