commit 9c18212f373aa929278a30a314f07fb392eb0cc4 Author: Sami Samhuri Date: Tue Mar 1 21:04:06 2011 -0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2b9969 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +src/*.o +bochs.out +src/kernel diff --git a/bochsrc b/bochsrc new file mode 100644 index 0000000..7920a4d --- /dev/null +++ b/bochsrc @@ -0,0 +1,9 @@ +megs: 32 +romimage: file=/usr/share/bochs/BIOS-bochs-latest +vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest +floppya: 1_44=/dev/loop0, status=inserted +boot: a +log: bochs.out +mouse: enabled=0 +clock: sync=realtime +cpu: ips=500000 diff --git a/floppy.img b/floppy.img new file mode 100644 index 0000000..68d3d64 Binary files /dev/null and b/floppy.img differ diff --git a/run_bochs.sh b/run_bochs.sh new file mode 100755 index 0000000..2af6d8d --- /dev/null +++ b/run_bochs.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +losetup /dev/loop0 floppy.img +bochs -f bochsrc +sleep 1 +losetup -d /dev/loop0 diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..3013e19 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,16 @@ +SOURCES=boot.o main.o common.o monitor.o + +CFLAGS=-nostdlib -nostdinc -fno-builtin -fno-stack-protector +LDFLAGS=-T link.ld +ASFLAGS=-f elf + +all: $(SOURCES) link + +clean: + -rm *.o kernel + +link: + ld $(LDFLAGS) -o kernel $(SOURCES) + +.s.o: + yasm $(ASFLAGS) $< diff --git a/src/boot.s b/src/boot.s new file mode 100644 index 0000000..45c7939 --- /dev/null +++ b/src/boot.s @@ -0,0 +1,45 @@ + ;; + ;; boot.s -- Kernel start location. Also defines multiboot header. + ;; Based on Bran's kernel development tutorial file start.asm + ;; + + MBOOT_PAGE_ALIGN equ 1<<0 ; Load kernel and modules on a page boundary + MBOOT_MEM_INFO equ 1<<1 ; Provide your kernel with memory info + MBOOT_HEADER_MAGIC equ 0x1BADB002 ; Multiboot Magic value + ;; NOTE: We do not use MBOOT_AOUT_KLUDGE. It means that GRUB does not + ;; pass us a symbol table. + MBOOT_HEADER_FLAGS equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO + MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS) + + + [BITS 32] ; All instructions should be 32-bit. + + [GLOBAL mboot] ; Make 'mboot' accessible from C. + [EXTERN code] ; Start of the '.text' section. + [EXTERN bss] ; Start of the .bss section. + [EXTERN end] ; End of the last loadable section. + +mboot: + dd MBOOT_HEADER_MAGIC ; GRUB will search for this value on each + ;; 4-byte boundary in your kernel file + dd MBOOT_HEADER_FLAGS ; How GRUB should load your file / settings + dd MBOOT_CHECKSUM ; To ensure that the above values are correct + + dd mboot ; Location of this descriptor + dd code ; Start of kernel '.text' (code) section. + dd bss ; End of kernel '.data' section. + dd end ; End of kernel. + dd start ; Kernel entry point (initial EIP). + + [GLOBAL start] ; Kernel entry point. + [EXTERN main] ; This is the entry point of our C code + +start: + push ebx ; Load multiboot header location + + ;; Execute the kernel: + cli ; Disable interrupts. + call main ; call our main() function. + jmp $ ; Enter an infinite loop, to stop the processor + ;; executing whatever rubbish is in the memory + ;; after our kernel! diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..7ea5246 --- /dev/null +++ b/src/common.c @@ -0,0 +1,36 @@ +// common.c -- Defines some global functions. +// From JamesM's kernel development tutorials. + +#include "common.h" + +// Write a byte out to the specified port. +void outb(u16int port, u8int value) +{ + + asm volatile ("outb %1, %0" : : "dN" (port), "a" (value)); + +} + + +u8int inb(u16int port) +{ + + u8int ret; + + asm volatile("inb %1, %0" : "=a" (ret) : "dN" (port)); + + return ret; + +} + + +u16int inw(u16int port) +{ + + u16int ret; + + asm volatile ("inw %1, %0" : "=a" (ret) : "dN" (port)); + + return ret; + +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..250b9c6 --- /dev/null +++ b/src/common.h @@ -0,0 +1,29 @@ +// common.h -- Defines typedefs and some global functions. +// From JamesM's kernel development tutorials. + +#ifndef COMMON_H +#define COMMON_H + +// Some nice typedefs, to standardise sizes across platforms. +// These typedefs are written for 32-bit X86. +typedef unsigned int u32int; + +typedef int s32int; + +typedef unsigned short u16int; + +typedef short s16int; + +typedef unsigned char u8int; + +typedef char s8int; + + +void outb(u16int port, u8int value); + +u8int inb(u16int port); + +u16int inw(u16int port); + + +#endif diff --git a/src/link.ld b/src/link.ld new file mode 100644 index 0000000..5a7e41d --- /dev/null +++ b/src/link.ld @@ -0,0 +1,32 @@ +/* Link.ld -- Linker script for the kernel - ensure everything goes in the */ +/* Correct place. */ +/* Original file taken from Bran's Kernel Development */ +/* tutorials: http://www.osdever.net/bkerndev/index.php. */ + +ENTRY(start) +SECTIONS +{ + .text 0x100000 : + { + code = .; _code = .; __code = .; + *(.text) + . = ALIGN(4096); + } + + .data : + { + data = .; _data = .; __data = .; + *(.data) + *(.rodata) + . = ALIGN(4096); + } + + .bss : + { + bss = .; _bss = .; __bss = .; + *(.bss) + . = ALIGN(4096); + } + + end = .; _end = .; __end = .; +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e2232ba --- /dev/null +++ b/src/main.c @@ -0,0 +1,18 @@ +// main.c -- Defines the C-code kernel entry point, calls initialisation routines. +// Made for JamesM's tutorials + +#include "monitor.h" + +int main(struct multiboot *mboot_ptr) +{ + monitor_clear(); + monitor_write("Hello, world!"); + + monitor_newline(); + monitor_write_dec(42); + + monitor_newline(); + monitor_write_hex(0xdeadbeef); + + return 0xdeadbeef; +} diff --git a/src/monitor.c b/src/monitor.c new file mode 100644 index 0000000..4ab4d98 --- /dev/null +++ b/src/monitor.c @@ -0,0 +1,174 @@ +#include "monitor.h" + +// The VGA framebuffer starts at 0xB8000. +u16int *video_memory = (u16int *)0xB8000; +u8int cursor_x = 0; +u8int cursor_y = 0; + +// Updates the hardware cursor. +static void move_cursor() +{ + // The screen is 80 characters wide... + u16int cursorLocation = cursor_y * 80 + cursor_x; + + outb(0x3D4, 14); + // Tell the VGA board we are setting the high cursor byte. + outb(0x3D5, cursorLocation >> 8); + // Send the high cursor byte. + outb(0x3D4, 15); + // Tell the VGA board we are setting the low cursor byte. + outb(0x3D5, cursorLocation); + // Send the low cursor byte. +} + +// Scrolls the text on the screen up by one line. +static void scroll() +{ + // Get a space character with the default colour attributes. + u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F); + u16int blank = 0x20 /* space */ | (attributeByte << 8); + + // Row 25 is the end, this means we need to scroll up + if (cursor_y >= 25) { + // Move the current text chunk that makes up the screen + // back in the buffer by a line + int i; + + for (i = 0*80; i < 24*80; i++) { + video_memory[i] = video_memory[i+80]; + } + + // The last line should now be blank. Do this by writing + // 80 spaces to it. + for (i = 24*80; i < 25*80; i++) { + video_memory[i] = blank; + } + + // The cursor should now be on the last line. + cursor_y = 24; + } +} + +// Writes a single character out to the screen. +void monitor_put(char c) +{ + // The background colour is black (0), the foreground is white (15). + u8int backColour = 0; + u8int foreColour = 15; + + // The attribute byte is made up of two nibbles - the lower being the + // foreground colour, and the upper the background colour. + u8int attributeByte = (backColour << 4) | (foreColour & 0x0F); + + // The attribute byte is the top 8 bits of the word we have to send to the + // VGA board. + u16int attribute = attributeByte << 8; + u16int *location; + + // Handle a backspace, by moving the cursor back one space + if (c == 0x08 && cursor_x) { + cursor_x--; + } + + // Handle a tab by increasing the cursor's X, but only to a point + // where it is divisible by 8. + else if (c == 0x09) { + cursor_x = (cursor_x+8) & ~(8-1); + } + + // Handle carriage return + else if (c == '\r') { + cursor_x = 0; + } + + + // Handle newline by moving cursor back to left and increasing the row + else if (c == '\n') { + cursor_x = 0; + cursor_y++; + } + + // Handle any other printable character. + else if(c >= ' ') { + location = video_memory + (cursor_y*80 + cursor_x); + *location = c | attribute; + cursor_x++; + } + + // Check if we need to insert a new line because we have reached the end + // of the screen. + if (cursor_x >= 80) { + cursor_x = 0; + cursor_y ++; + } + + // Scroll the screen if needed. + scroll(); + + // Move the hardware cursor. + move_cursor(); +} + +// Clears the screen, by copying lots of spaces to the framebuffer. +void monitor_clear() +{ + // Make an attribute byte for the default colours + u8int attributeByte = (0 /*black*/ << 4) | (15 /*white*/ & 0x0F); + u16int blank = 0x20 /* space */ | (attributeByte << 8); + int i; + for (i = 0; i < 80*25; i++) { + video_memory[i] = blank; + } + + // Move the hardware cursor back to the start. + cursor_x = 0; + cursor_y = 0; + move_cursor(); +} + +// Outputs a null-terminated ASCII string to the monitor. +void monitor_write(char *c) +{ + int i = 0; + while (c[i]) { + monitor_put(c[i++]); + } +} + +void monitor_newline() +{ + while (cursor_x > 0) monitor_put(' '); +} + +void monitor_write_hex(u32int n) +{ + static char hex_chars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' }; + u32int mask = 0xf0000000; + int i = 28; + while (i >= 0) { + monitor_put(hex_chars[(n & mask) >> i]); + mask >>= 4; + i -= 4; + } +} + +u32int pow(base, exp) +{ + u32int n = base; + if (exp == 0) return 1; + while (exp > 1) { + n *= base; + exp--; + } + return n; +} + +void monitor_write_dec(u32int n) +{ + static char dec_chars[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + int i = 7; + while (i >= 0) { + monitor_put(dec_chars[(n / pow(10, i--)) % 10]); + } +} diff --git a/src/monitor.h b/src/monitor.h new file mode 100644 index 0000000..53e6804 --- /dev/null +++ b/src/monitor.h @@ -0,0 +1,27 @@ +// monitor.h -- Defines the interface for monitor.h +// From JamesM's kernel development tutorials. + +#ifndef MONITOR_H +#define MONITOR_H + +#include "common.h" + +// Write a single character out to the screen. +void monitor_put(char c); + +// Clear the screen to all black. +void monitor_clear(); + +// Output a null-terminated ASCII string to the monitor. +void monitor_write(char *c); + +// Move the cursor to the next line +void monitor_newline(); + +// Output a number to the screen in hexadecimal notation. +void monitor_write_hex(u32int n); + +// Output a number to the screen in decimal notation. +void monitor_write_dec(u32int n); + +#endif // MONITOR_H diff --git a/update_image.sh b/update_image.sh new file mode 100755 index 0000000..0e96782 --- /dev/null +++ b/update_image.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +losetup /dev/loop0 floppy.img +mount /dev/loop0 /mnt +cp src/kernel /mnt/kernel +sleep 1 +umount /mnt +losetup -d /dev/loop0