start of 0.0.9 branch, using multiboot this time

This commit is contained in:
Benji Dial 2019-12-24 22:31:22 -05:00
parent a947a7a143
commit f5f0f5ddae
15 changed files with 325 additions and 424 deletions

View file

@ -1,18 +1,14 @@
floppy: bootloader fs floppy: kernel
mkfs.fat -C -f 1 -F 12 -n "PORTLAND OS" -R 2 -S 512 out/floppy.img 1440 #TODO
mkdir out/floppy_mount
mount out/floppy.img out/floppy_mount
cp out/fs/* out/floppy_mount/
umount out/floppy_mount
dd if=obj/bootloader.bin of=out/floppy.img bs=1 seek=62 conv=notrunc
bootloader: obj kernel: obj out
nasm src/bootloader.asm -o obj/bootloader.bin nasm src/kernel/stub.asm -o obj/kstub.o -f elf32
gcc -c src/kernel/files.c -o obj/kfiles.o -ffreestanding -nostdlib -m32
kernel: obj fs gcc -c src/kernel/main.c -o obj/kmain.o -ffreestanding -nostdlib -m32
gcc src/kernel/*.c -o obj/kernel.elf -ffreestanding -nostdlib -m32 -fno-asynchronous-unwind-tables gcc -c src/kernel/mem.c -o obj/kmem.o -ffreestanding -nostdlib -m32
ld obj/kernel.elf -o obj/kernel-stripped.elf -T src/kernel/link.ld -s --orphan-handling=discard -m elf_i386 gcc -c src/kernel/proc.c -o obj/kproc.o -ffreestanding -nostdlib -m32
objcopy obj/kernel-stripped.elf out/fs/kernel.sys -O binary gcc -c src/kernel/vga.c -o obj/kvga.o -ffreestanding -nostdlib -m32
ld obj/k*.o -o out/kernel.elf -T src/kernel/link.ld -s --orphan-handling=discard -m elf_i386
clean: clean:
rm -r obj out rm -r obj out

View file

@ -1,277 +0,0 @@
;Copyright 2019 Benji Dial
;Permission to use, copy, modify, and/or distribute this
;software for any purpose with or without fee is hereby
;granted, provided that the above copyright notice and this
;permission notice appear in all copies.
;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
;ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
;EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
;INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
;WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
;WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
;TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
;USE OR PERFORMANCE OF THIS SOFTWARE.
kload equ 0x0010_0000
global_info:;0x0500 - 0x05ff (0x0515)
.fat equ 0x0500;dword - pointer
.root_dir equ 0x0504;dword - pointer
.low_mem equ 0x0508;word - usable memory from 0 to 1MiB in kiB
.mid_mem equ 0x050a;word - usable memory from 1MiB to 16MiB in kiB
.mem_used equ 0x050c;word - used memory from 0 to 1MiB in kiB
.kernel_s equ 0x050e;word - kernel image length in kiB
;dword - kernel use
.high_mem equ 0x0514;word - usable memory from 16MiB up in 64s of kiB
fat_header:;0x7c03 - 0x7c3d
.oem_name equ 0x7c03;mkfs.fat -
.bytes_per_sector equ 0x7c0b;0x0200 -
.sectors_per_cluster equ 0x7c0d;0x01 -
.reserved_sectors equ 0x7c0e;0x0002 - handled
.n_fats equ 0x7c10;0x01 -
.root_dir_entries equ 0x7c11; -
.n_sectors equ 0x7c13;0x0b40 -
.media_type equ 0x7c15; -
.sectors_per_fat equ 0x7c16; - handled
.sectors_per_track equ 0x7c18;0x0012 -
.sides equ 0x7c1a;0x0002 -
.hidden_sectors equ 0x7c1c;0x0000_0000 -
.long_sectors equ 0x7c20;0x0000_0000 -
.drive_number equ 0x7c24; - ignored, used as scratch for real drive number
.flags equ 0x7c25; -
.signature equ 0x7c26;0x29 - errors on other values
.id equ 0x7c27; -
.label equ 0x7c2b;PORTLAND OS -
.fs_type equ 0x7c36;FAT12 - errors on other values
error_codes:
.bad_fat_header equ 0o000
.insufficient_memory equ 0o001
.no_kernel equ 0o002
.kernel_too_big equ 0o003
org 0x7c3e
bits 16
;Enable A20 line
in al, 0x92
or al, 0x02
out 0x92, al
;Load second sector of bootloader
mov ah, 0x42
mov si, dap
int 0x13
;Check FAT signature
test byte [fat_header.signature], 0x29
jne bad_fat_header
test word [fat_header.fs_type], 0x4146;FA
jne bad_fat_header
test word [fat_header.fs_type + 2], 0x3154;T1
jne bad_fat_header
test word [fat_header.fs_type + 4], 0x2032;2
jne bad_fat_header
test word [fat_header.fs_type + 6], 0x2020;
jne bad_fat_header
;Store boot drive ID for later
mov byte [fat_header.drive_number], dl
memory:
;Get available low memory
int 0x12
mov word [global_info.low_mem], ax
mov word [global_info.mem_used], 0x0020
;Get available mid and high memory
xor dx, dx
mov ax, 0xe801
int 0x15
test dx, dx
jnz .got
mov cx, ax
mov dx, bx
.got:
mov word [global_info.mid_mem], cx
mov word [global_info.high_mem], dx
;Load FAT
mov ax, word [fat_header.reserved_sectors]
mov word [dap.start], ax
xor eax, eax
mov ax, word [fat_header.sectors_per_fat]
call load_low
mov dword [global_info.fat], ebx
load_root:
;Load root directory
mov ax, word [fat_header.sectors_per_fat]
xor dh, dh
mov dl, word [fat_header.n_fats]
mul dx
add ax, [fat_header.reserved_sectors]
jnc .no_inc
inc dx
.no_inc:
mov word [dap.start], ax
mov word [dap.start + 2], dx
mov ax, word [fat_header.root_dir_entries]
shr ax, 4
call load_low
mov dword [global_info.root_dir], ebx
;Calculate end of root directory
xor ecx, ecx
mov cx, word [fat_header.root_dir_entries]
shl ecx, 5
add ecx, ebx
jc insufficient_memory
find_kernel:
mov eax, 0x6e72_656b;kern
mov edx, 0x2020_6c65;el
.loop:
;Check name
test dword [ebx], eax
jne .next
test dword [ebx + 4], edx
jne .next
test word [ebx + 8], 0x7973;sy
jne .next
test byte [ebx + 10], 0x73;s
je .found
.next:
;Next record
add ebx, 32
test ebx, ecx
jne .loop
;Got to end of directory
mov dl, error_codes.no_kernel
jmp error
;ebx is pointer to entry
;word [ebx + 26] is first cluster
;dword [ebx + 28] is size
.found:
;Save size for later
mov eax, dword [ebx + 28]
shr eax, 10
test eax, 0x003f_0000
jz .store_size
mov dl, error_codes.kernel_too_big
jmp error
.store_size:
mov word [global_info.kernel_s], ax
;Save sector number for later
mov cx, [ebx + 26]
;find 1kiB buffer
mov ax, 2
mov byte [load_low.ret_with_segment], 0xc3;ret
call load_low
shl ebx, 4
load_kernel:
load_low:
;ax in : number of sectors
;qword [dap.start] in : starting sector
;Store length in DAP
mov word [dap.length], ax
;Calculate kiB used
dec ax
shr ax, 1
inc ax
mov dx, ax
add ax, word [global_info.mem_usage]
;Fail if not enough is available
jc insufficient_memory
cmp ax, word [global_info.low_mem]
jg insufficient_memory
;Check if address will fit in DAP
test ah, ah
jnz insufficient_memory
;Commit usage
mov word [global_info.low_mem_usage], ax
;Put address into DAP
xor ebx, ebx
mov bh, al
shr bx, 2
mov word [dap.segment], bx
mov word [dap.offset], 0x0000
.ret_with_segment:
;Load from disk
mov si, dap
mov ah, 0x42
int 0x13
shl ebx, 4
ret
bad_fat_header:
mov dl, error_codes.bad_fat_header
jmp error
insufficient_memory:
mov dl, error_codes.insufficient_memory
jmp error
error:
;Print error code (in octal)
mov ax, 0xb800
mov ds, ax
mov word [0], 0x0f72;E
mov ax, 0x0f00
mov al, dl
and al, 0x07
or al, 0x30
mov word [6], ax;bottom digit
shr dl, 3
mov al, dl
and al, 0x07
or al, 0x30
mov word [4], ax;middle digit
shr dl, 3
mov al, dl
or al, 0x30
mov word [2], ax;top digit
cli
.halt:
hlt
jmp .halt
gdt:
dw 0x28
dd gdt + 6
dq 0x0000_0000_0000_0000
dq 0x0040_9a00_0000_7fff;0x000000 - 0x007fff
dq 0x0040_9200_0000_7fff
dq 0x00c0_9a00_8000_0ff7;0x008000 - 0xffffff
dq 0x00c0_9200_8000_0ff7
dap:
dw 0x0010
.length dw 0x0001
.offset dw 0x7e00
.segment dw 0x0000
.start dq 0x0000_0000_0000_0001
memory_usage:
.low dw ;word - used memory from 0 to 1MiB in kiB
.mid dw 0x0000;word - used memory from 1MiB to 16MiB in kiB
.high dw 0x0000;word - used memory from 16MiB up in 64s of kiB

View file

@ -24,7 +24,7 @@ uint16_t open_file(uint8_t *name) {
} }
void close_file(uint16_t handle) { void close_file(uint16_t handle) {
FILE_HANDLES[handle].first_sector = 0; file_table[handle].first_sector = 0;
} }
void read_file(uint16_t handle, uint32_t length, void *buffer) { void read_file(uint16_t handle, uint32_t length, void *buffer) {

View file

@ -22,14 +22,14 @@ OF THIS SOFTWARE.
#ifndef FILES_H #ifndef FILES_H
#define FILES_H #define FILES_H
struct file_handle_info { struct file_info {
uint16_t first_sector; uint16_t first_sector;
uint16_t current_sector; uint16_t current_sector;
uint8_t *io_buffer; uint8_t *io_buffer;
uint32_t position; uint32_t position;
}; };
#define FILE_HANDLES ((struct file_handle_info *)*(uint32_t *)0x0000050c) struct file_info *file_table;
uint16_t open_file(uint8_t *name); uint16_t open_file(uint8_t *name);
void close_file(uint16_t handle); void close_file(uint16_t handle);
void read_file(uint16_t handle, uint32_t length, void *buffer); void read_file(uint16_t handle, uint32_t length, void *buffer);

View file

@ -1,13 +1,8 @@
MEMORY {
kload : ORIGIN = 0x01000000, LENGTH = 0x01000000
}
SECTIONS { SECTIONS {
. = 0x01000000; . = 0x01000000;
.text : { .mb_header : ALIGN(8) { *(.mb_header) }
_start = .; .text : ALIGN(512) { *(.text) }
*(.text) .rodata : ALIGN(512) { *(.rodata) }
} >kload .data : ALIGN(512) { *(.data) }
.rodata : { *(.rodata) } >kload .bss : ALIGN(512) { *(.bss) }
.data : { *(.data) *(.bss) } >kload
} }

View file

@ -21,33 +21,177 @@ OF THIS SOFTWARE.
#include "files.h" #include "files.h"
#include "mem.h" #include "mem.h"
#include "proc.h" #include "proc.h"
#include "misc.h" #include <stdbool.h>
void _start(void) { extern uint32_t info_pointer;
*(uint16_t *)0x0000200e = 0x0000;
*(uint32_t *)0x0000050c = (uint32_t)allocate_pages(16 * sizeof(struct file_handle_info), 2); enum tag_type {
for (struct file_handle_info *i = FILE_HANDLES, *l = FILE_HANDLES + 65536; i < l; ++i) BOOT_COMMAND = 1,
i->first_sector = 0; LOADER_NAME = 2,
BOOT_MODULES = 3,
MEMORY_INFO = 4,
BOOT_DEVICE = 5,
MEMORY_MAP = 6,
VBE_INFO = 7,
FBUF_INFO = 8,
ELF_SYMBOLS = 9,
APM_TABLE = 10,
EFI_I386_TABLE = 11,
EFI_AMD64_TABLE = 12,
SMBIOS_TABLE = 13,
RSDP_ACPI1 = 14,
RSDP_ACPI2 = 15,
NETWORK_INFO = 16,
EFI_MEMORY_MAP = 17,
EFI_SERVICES = 18,
EFI_I386_HANDLE = 19,
EFI_AMD64_HANDLE = 20,
IMAGE_BASE_ADDR = 21
};
*(uint32_t *)0x00000510 = (uint32_t)allocate_pages(16 * sizeof(struct proc_info), 2); struct tag_start {
for (struct proc_info *i = PROCS, *l = PROCS + 65536; i < l; ++i) uint32_t type;
i->memory_start = 0; uint32_t size;
uint8_t rest;
} __attribute__ ((__packed__));
struct boot_device_tag {
uint32_t bios_device;
uint32_t partition;
uint32_t subpartition;
} __attribute__ ((__packed__));
enum mem_type {
AVAILABLE = 1,
ACPI = 3,
PRESERVE = 4,
DEFECTIVE = 5
};
struct boot_device_tag boot_device;
bool have_boot_device = false;
bool have_mmap = false;
enum error_codes {
NO_BOOT_DEVICE = 0,
NO_MMAP = 1,
INSUFF_MEMORY = 2
};
uint32_t main(void) {
uint32_t info_size = *(uint32_t *)info_pointer;
struct tag_start *tag_pointer = (struct tag_start *)(info_pointer + 2);
while (tag_pointer->type) {
switch (tag_pointer->type) {
case BOOT_DEVICE:
boot_device = *(struct boot_device_tag *)&tag_pointer->rest;
have_boot_device = true;
put_sz("Boot device: 0x");
put_32_hex(boot_device.bios_device);
if (boot_device.partition != 0xffffffff) {
put_sz(", 0x");
put_32_hex(boot_device.partition);
if (boot_device.subpartition != 0xffffffff) {
put_sz(", 0x");
put_32_hex(boot_device.subpartition);
}
}
put_char('\n');
break;
case MEMORY_MAP:
mmap_start = (struct mmap_entry *)((uint32_t)&tag_pointer->rest + 8);
uint32_t size = *(uint32_t *)&tag_pointer->rest;
struct mmap_entry *next = mmap_start;
struct mmap_entry **fill_last = &mmap_start;
uint32_t usable = 0;
while (next) {
if (!(next->base & 0xffffffff00000000)) {
*fill_last = next;
fill_last = &next->next;
if ((next->base + next->length - 1) & 0xffffffff00000000)
next->length = 1 + ~(next->base);
put_sz("Memory: 0x");
put_32_hex((uint32_t)(next->base >> 32));
put_char('_');
put_32_hex((uint32_t)next->base);
put_sz(" - ");
put_32_hex((uint32_t)(next->length >> 32));
put_char('_');
put_32_hex((uint32_t)next->length);
switch (next->whose) {
case AVAILABLE:
put_sz(": usable\n");
next->whose = FREE;
usable += next->length;
break;
case ACPI:
put_sz(": ACPI info\n");
next->whose = HARDWARE;
break;
case PRESERVE:
put_sz(": hardware use\n");
next->whose = HARDWARE;
break;
case DEFECTIVE:
put_sz(": defective\n");
next->whose = HARDWARE;
break;
default:
put_sz(": unrecognized type, assuming hardware use\n");
next->whose = HARDWARE;
break;
}
}
next = next->next = (struct mmap_entry *)((uint32_t)next + size);
}
put_sz("Total usable memory: 0x");
put_32_hex(usable);
put_char('\n');
bool clean;
do {
clean = true;
for (struct mmap_entry *current = mmap_start; current; current = current->next)
for (struct mmap_entry *against = mmap_start; against; against = against->next)
if ((current->base + current->length == against->base) &&
(current->whose == against->whose)) {
current->length += against->length;
if (against == mmap_start)
mmap_start = against->next;
else {
for (current = mmap_start; current->next != against; current = current->next)
;
current->next = against->next;
}
clean = false;
}
} while (clean);
have_mmap = true;
break;
uint16_t pages_free = 0, pages_total = 0;
for (uint16_t *i = MMAP; i < MMAP + 0x1000; ++i)
switch (*i) {
case 1:
continue;
case 0:
++pages_free;
default: default:
++pages_total; put_sz("Ignoring multiboot tag 0x");
put_32_hex(tag_pointer->type);
put_char('\n');
} }
put_16(pages_free); tag_pointer = (struct tag_start *)((uint8_t *)tag_pointer + tag_pointer->size);
put_sz(" of "); };
put_16(pages_total);
put_sz(" pages free.\n"); if (!have_boot_device)
return NO_BOOT_DEVICE;
if (!have_mmap)
return NO_MMAP;
if (!((proc_table = allocate_block(sizeof(struct proc_info) * 65536, KERNEL)) &&
(file_table = allocate_block(sizeof(struct file_info) * 65536, KERNEL))))
return INSUFF_MEMORY;
;
put_sz("Welcome to Portland version 0.0.8!\n"); put_sz("Welcome to Portland version 0.0.8!\n");
while (1) while (1)

View file

@ -19,23 +19,10 @@ OF THIS SOFTWARE.
#include "mem.h" #include "mem.h"
void *allocate_pages(uint16_t n_pages, uint16_t proc_n) { void *allocate_block(uint32_t size, uint16_t proc_n) {
for (uint16_t *i = MMAP, *l = MMAP + 0x1000 - proc_n; ++i; i <= l) //TODO
outer_for:
if (!*i) {
for (uint16_t j = 1; j < n_pages; ++j)
if (i[j]) {
i += j + 1;
goto outer_for;
}
for (uint16_t j = 0; j < n_pages; ++j)
i[j] = proc_n;
return (void *)((i - MMAP) * 0x1000);
}
return (void *)0;
} }
void deallocate_pages(void *from, uint16_t n_pages) { void deallocate_block(void *start) {
for (uint16_t *mb = MMAP + (uint32_t)from / 0x1000, *l = mb + n_pages; mb < l; ++mb) //TODO
*mb = 0;
} }

View file

@ -22,8 +22,21 @@ OF THIS SOFTWARE.
#ifndef MEM_H #ifndef MEM_H
#define MEM_H #define MEM_H
#define MMAP ((uint16_t *)0x00002000) enum special_mmap_codes {
void *allocate_pages(uint16_t n_pages, uint16_t proc_n); FREE = 0,
void deallocate_pages(void *from, uint16_t n_pages); HARDWARE = 1,
KERNEL = 2
};
struct mmap_entry {
uint64_t base;
uint64_t length;
uint32_t whose;
struct mmap_entry *next;
} __attribute__ ((__packed__));
struct mmap_entry *mmap_start;
void *allocate_block(uint32_t size, uint16_t proc_n);
void deallocate_block(void *start);
#endif #endif

View file

@ -1,46 +0,0 @@
/*
Copyright 2019 Benji Dial
Permission to use, copy, modify, and/or distribute this
software for any purpose with or without fee is hereby
granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
*/
#include "misc.h"
#include "vga.h"
#include <stdbool.h>
void put_16(uint16_t n) {
bool s = false;
if (n / 10000) {
put_char((uint8_t)'0' + n / 10000);
s = true;
}
n %= 10000;
if (n / 1000 || s) {
put_char((uint8_t)'0' + n / 1000);
s = true;
}
n %= 1000;
if (n / 100 || s) {
put_char((uint8_t)'0' + n / 100);
s = true;
}
n %= 100;
if (n / 10 || s) {
put_char((uint8_t)'0' + n / 10);
s = true;
}
put_char((uint8_t)'0' + n % 10);
}

View file

@ -1,27 +0,0 @@
/*
Copyright 2019 Benji Dial
Permission to use, copy, modify, and/or distribute this
software for any purpose with or without fee is hereby
granted, provided that the above copyright notice and this
permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
OF THIS SOFTWARE.
*/
#include <stdint.h>
#ifndef MISC_H
#define MISC_H
void put_16(uint16_t n);
#endif

View file

@ -25,9 +25,10 @@ uint16_t new_proc(uint8_t *file) {
uint16_t handle = open_file(file); uint16_t handle = open_file(file);
if (handle) if (handle)
for (uint16_t id = 3; id; ++id) for (uint16_t id = 3; id; ++id)
if (!PROCS[id].memory_start) { if (!proc_table[id].memory_start) {
uint32_t size = get_size(id); uint32_t size = get_size(id);
void *mem = PROCS[id].memory_start = allocate_pages(PROCS[id].n_pages = (size - 1) / 4096 + 1, id); void *mem;
proc_table[id].memory_end = size + (proc_table[id].memory_start = allocate_block(size, id));
read_file(handle, size, mem); read_file(handle, size, mem);
close_file(handle); close_file(handle);
//Process file header and make new process //Process file header and make new process
@ -38,6 +39,6 @@ uint16_t new_proc(uint8_t *file) {
} }
void end_proc(uint16_t id) { void end_proc(uint16_t id) {
deallocate_pages(PROCS[id].memory_start, PROCS[id].n_pages); deallocate_block(proc_table[id].memory_start);
PROCS[id].memory_start = 0; proc_table[id].memory_start = 0;
} }

View file

@ -24,10 +24,10 @@ OF THIS SOFTWARE.
struct proc_info { struct proc_info {
void *memory_start; void *memory_start;
uint16_t n_pages; void *memory_end;
}; };
#define PROCS ((struct proc_info *)*(uint32_t *)0x00000510) struct proc_info *proc_table;
uint16_t new_proc(uint8_t *file); uint16_t new_proc(uint8_t *file);
void end_proc(uint16_t id); void end_proc(uint16_t id);

76
src/kernel/stub.asm Normal file
View file

@ -0,0 +1,76 @@
;Copyright 2019 Benji Dial
;Permission to use, copy, modify, and/or distribute this
;software for any purpose with or without fee is hereby
;granted, provided that the above copyright notice and this
;permission notice appear in all copies.
;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
;ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
;IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
;EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
;INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
;RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
;ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
;ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
;OF THIS SOFTWARE.
extern main
section .mb_header
dd 0xe852_50d6;magic
dd 0x0000_0000;architecture - i386
dd mb_end - $$;length
dd 0x17adaf2a - mb_end + $$;check
;tags
dw 0x0001;info request
dw 0x0000;flags
dd mb_end - $$ - 16
dd 5;boot device
dd 6;memory map
mb_end:
section .text
bits 32
_start:
mov dword [info_pointer], ebx
mov esp, stack
call main
mov edx, eax
mov eax, 0x20f0_20f0
mov ebx, 0x000b_8000
mov ecx, 0x000b_8fa0
clear_screen_loop:
mov dword [ebx], eax
add ebx, 4
test ebx, ecx
jne clear_screen_loop
mov dword [0x000b_8000], 0xf072_f045
mov dword [0x000b_8004], 0xf06f_f072
mov dword [0x000b_8008], 0xf020_f072
mov ebx, 0x000b_8022
error_number_loop:
mov al, dl
and al, 0x07
or al, 0x30
mov byte [ebx], al
sub ebx, 2
shr edx, 3
test ebx, 0x000b_800a
jne error_number_loop
cli
halt:
hlt
jmp halt
section .bss
global info_pointer
info_pointer resd 1
resb 0x1000 - $ + $$
stack:

View file

@ -18,6 +18,7 @@ OF THIS SOFTWARE.
*/ */
#include "vga.h" #include "vga.h"
#include <stdbool.h>
uint16_t cursor_pos = 0; uint16_t cursor_pos = 0;
uint8_t color = 0xf0; uint8_t color = 0xf0;
@ -62,6 +63,42 @@ void put_sz(uint8_t *sz) {
put_char(*(sz++)); put_char(*(sz++));
} }
void put_16(uint16_t n) {
bool s = false;
if (n / 10000) {
put_char((uint8_t)'0' + n / 10000);
s = true;
}
n %= 10000;
if (n / 1000 || s) {
put_char((uint8_t)'0' + n / 1000);
s = true;
}
n %= 1000;
if (n / 100 || s) {
put_char((uint8_t)'0' + n / 100);
s = true;
}
n %= 100;
if (n / 10 || s) {
put_char((uint8_t)'0' + n / 10);
s = true;
}
put_char((uint8_t)'0' + n % 10);
}
void put_32_hex(uint32_t n) {
for (uint8_t i = 0; i < 4; ++i) {
put_char(n / 0xf0000000 + (n < 0xa0000000 ? (uint8_t)'0' : (uint8_t)'a' - 1));
n <<= 4;
}
put_char('_');
for (uint8_t i = 0; i < 4; ++i) {
put_char(n / 0xf0000000 + (n < 0xa0000000 ? (uint8_t)'0' : (uint8_t)'a' - 1));
n <<= 4;
}
}
void move_cursor(uint8_t col, uint8_t row) { void move_cursor(uint8_t col, uint8_t row) {
cursor_pos = (col + row * cols) * 2; cursor_pos = (col + row * cols) * 2;
} }

View file

@ -25,6 +25,8 @@ OF THIS SOFTWARE.
#define VGA_BUFFER ((uint8_t *)0x000b8000) #define VGA_BUFFER ((uint8_t *)0x000b8000)
void put_char(uint8_t ch); void put_char(uint8_t ch);
void put_sz(uint8_t *s); void put_sz(uint8_t *s);
void put_16(uint16_t n);
void put_32_hex(uint32_t n);
void move_cursor(uint8_t col, uint8_t row); void move_cursor(uint8_t col, uint8_t row);
void set_color(uint8_t c); void set_color(uint8_t c);