Repository: MaaSTaaR/539kernel
Branch: master
Commit: 82f8164194ce
Files: 93
Total size: 103.0 KB
Directory structure:
gitextract_ir_g73hk/
├── README.md
├── evolution_by_versions/
│ ├── .gitignore
│ ├── 01_539kernel_bootloader/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ └── simple_kernel.asm
│ ├── 03_539kernel_progenitor/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ └── starter.asm
│ ├── 04_539kernel_version_t/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ ├── process.c
│ │ ├── process.h
│ │ ├── scheduler.c
│ │ ├── scheduler.h
│ │ ├── screen.c
│ │ ├── screen.h
│ │ └── starter.asm
│ ├── 05_539kernel_version_g/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── heap.c
│ │ ├── heap.h
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ ├── paging.c
│ │ ├── paging.h
│ │ ├── process.c
│ │ ├── process.h
│ │ ├── scheduler.c
│ │ ├── scheduler.h
│ │ ├── screen.c
│ │ ├── screen.h
│ │ └── starter.asm
│ └── 06_539kernel_version_ne/
│ ├── Makefile
│ ├── ata.c
│ ├── ata.h
│ ├── bochs
│ ├── bootstrap.asm
│ ├── filesystem.c
│ ├── filesystem.h
│ ├── gdt.asm
│ ├── heap.c
│ ├── heap.h
│ ├── idt.asm
│ ├── linker.ld
│ ├── main.c
│ ├── paging.c
│ ├── paging.h
│ ├── process.c
│ ├── process.h
│ ├── scheduler.c
│ ├── scheduler.h
│ ├── screen.c
│ ├── screen.h
│ ├── starter.asm
│ ├── str.c
│ └── str.h
└── src/
├── .gitignore
├── Makefile
├── README
├── ata.c
├── ata.h
├── bochs
├── bootstrap.asm
├── filesystem.c
├── filesystem.h
├── gdt.asm
├── heap.c
├── heap.h
├── idt.asm
├── linker.ld
├── main.c
├── paging.c
├── paging.h
├── process.c
├── process.h
├── scheduler.c
├── scheduler.h
├── screen.c
├── screen.h
├── simple_kernel.asm
├── starter.asm
├── str.c
└── str.h
================================================
FILE CONTENTS
================================================
================================================
FILE: README.md
================================================
539kernel is a simple x86 32bit educational kernel which has been written especially for the book "**[A Journey in Creating an Operating System Kernel](https://539kernel.com)**" which is available freely on <https://539kernel.com>.
* `src/` contains the last version of 539kernel.
* `evolution_by_versions/` contains the version of 539kernel while it's under development through the different chapters in the book.
================================================
FILE: evolution_by_versions/.gitignore
================================================
# Created by https://www.gitignore.io/api/c
# Edit at https://www.gitignore.io/?templates=c
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
*.bin
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# End of https://www.gitignore.io/api/c
*.img
================================================
FILE: evolution_by_versions/01_539kernel_bootloader/Makefile
================================================
ASM = nasm
BOOTSTRAP_FILE = bootstrap.asm
KERNEL_FILE = simple_kernel.asm
build: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f bin $(KERNEL_FILE) -o kernel.o
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=kernel.o of=kernel.img bs=512
qemu-system-x86_64 -s kernel.img
clean:
rm -f *.o
================================================
FILE: evolution_by_versions/01_539kernel_bootloader/bootstrap.asm
================================================
start:
mov ax, 07C0h
mov ds, ax
mov si, title_string
call print_string
mov si, message_string
call print_string
call load_kernel_from_disk
jmp 0900h:0000
load_kernel_from_disk:
mov ax, 0900h
mov es, ax
mov ah, 02h
mov al, 01h
mov ch, 0h
mov cl, 02h
mov dh, 0h
mov dl, 80h
mov bx, 0h
int 13h
jc kernel_load_error
ret
kernel_load_error:
mov si, load_error_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; Reading current cursor position
mov ah, 03h
mov bh, 0
int 10h
; Move the cursor to the beginning
mov ah, 02h
mov dl, 0
int 10h
ret
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
times 510-($-$$) db 0
dw 0xAA55
================================================
FILE: evolution_by_versions/01_539kernel_bootloader/simple_kernel.asm
================================================
start:
mov ax, cs
mov ds, ax
; --- ;
mov si, hello_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je done
int 10h
jmp print_char
done:
ret
hello_string db 'Hello World!, From Simple Assembly 539kernel!', 0
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/Makefile
================================================
ASM = nasm
CC = gcc
BOOTSTRAP_FILE = bootstrap.asm
INIT_KERNEL_FILES = starter.asm
KERNEL_FILES = main.c
KERNEL_FLAGS = -Wall -m32 -c -ffreestanding -fno-asynchronous-unwind-tables -fno-pie
KERNEL_OBJECT = -o kernel.elf
build: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
ld -melf_i386 -Tlinker.ld starter.o kernel.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=5
dd seek=6 conv=sync if=/dev/zero of=kernel.img bs=512 count=2046
qemu-system-x86_64 -s kernel.img
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/bootstrap.asm
================================================
start:
mov ax, 07C0h
mov ds, ax
mov si, title_string
call print_string
mov si, message_string
call print_string
call load_kernel_from_disk
jmp 0900h:0000
load_kernel_from_disk:
mov ax, [curr_sector_to_load]
sub ax, 2
mov bx, 512d
mul bx
mov bx, ax
mov ax, 0900h
mov es, ax
mov ah, 02h
mov al, 1h
mov ch, 0h
mov cl, [curr_sector_to_load]
mov dh, 0h
mov dl, 80h
int 13h
jc kernel_load_error
sub byte [number_of_sectors_to_load], 1
add byte [curr_sector_to_load], 1
cmp byte [number_of_sectors_to_load], 0
jne load_kernel_from_disk
ret
kernel_load_error:
mov si, load_error_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; Reading current cursor position
mov ah, 03h
mov bh, 0
int 10h
; Move the cursor to the beginning
mov ah, 02h
mov dl, 0
int 10h
ret
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
number_of_sectors_to_load db 10d
curr_sector_to_load db 2d
times 510-($-$$) db 0
dw 0xAA55
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/gdt.asm
================================================
gdt:
null_descriptor : dw 0, 0, 0, 0
kernel_code_descriptor : dw 0xffff, 0x0000, 0x9a00, 0x00cf
kernel_data_descriptor : dw 0xffff, 0x0000, 0x9200, 0x00cf
userspace_code_descriptor : dw 0xffff, 0x0000, 0xfa00, 0x00cf
userspace_data_descriptor : dw 0xffff, 0x0000, 0xf200, 0x00cf
gdtr:
gdt_size_in_bytes : dw ( 5 * 8 )
gdt_base_address : dd gdt
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/idt.asm
================================================
isr_0:
cli
push 0
jmp isr_basic
isr_1:
cli
push 1
jmp isr_basic
isr_2:
cli
push 2
jmp isr_basic
isr_3:
cli
push 3
jmp isr_basic
isr_4:
cli
push 4
jmp isr_basic
isr_5:
cli
push 5
jmp isr_basic
isr_6:
cli
push 6
jmp isr_basic
isr_7:
cli
push 7
jmp isr_basic
isr_8:
cli
push 8
jmp isr_basic
isr_9:
cli
push 9
jmp isr_basic
isr_10:
cli
push 10
jmp isr_basic
isr_11:
cli
push 11
jmp isr_basic
isr_12:
cli
push 12
jmp isr_basic
isr_13:
cli
push 13
jmp isr_basic
isr_14:
cli
push 14
jmp isr_basic
isr_15:
cli
push 15
jmp isr_basic
isr_16:
cli
push 16
jmp isr_basic
isr_17:
cli
push 17
jmp isr_basic
isr_18:
cli
push 18
jmp isr_basic
isr_19:
cli
push 19
jmp isr_basic
isr_20:
cli
push 20
jmp isr_basic
isr_21:
cli
push 21
jmp isr_basic
isr_22:
cli
push 22
jmp isr_basic
isr_23:
cli
push 23
jmp isr_basic
isr_24:
cli
push 24
jmp isr_basic
isr_25:
cli
push 25
jmp isr_basic
isr_26:
cli
push 26
jmp isr_basic
isr_27:
cli
push 27
jmp isr_basic
isr_28:
cli
push 28
jmp isr_basic
isr_29:
cli
push 29
jmp isr_basic
isr_30:
cli
push 30
jmp isr_basic
isr_31:
cli
push 31
jmp isr_basic
isr_32:
cli
push 32
jmp irq_basic
isr_33:
cli
push 33
jmp irq_basic
isr_34:
cli
push 34
jmp irq_basic
isr_35:
cli
push 35
jmp irq_basic
isr_36:
cli
push 36
jmp irq_basic
isr_37:
cli
push 37
jmp irq_basic
isr_38:
cli
push 38
jmp irq_basic
isr_39:
cli
push 39
jmp irq_basic
isr_40:
cli
push 40
jmp irq_basic
isr_41:
cli
push 41
jmp irq_basic
isr_42:
cli
push 42
jmp irq_basic
isr_43:
cli
push 43
jmp irq_basic
isr_44:
cli
push 44
jmp irq_basic
isr_45:
cli
push 45
jmp irq_basic
isr_46:
cli
push 46
jmp irq_basic
isr_47:
cli
push 47
jmp irq_basic
isr_48:
cli
push 48
jmp irq_basic
isr_basic:
call interrupt_handler
pop eax
sti
iret
irq_basic:
call interrupt_handler
mov al, 0x20
out 0x20, al
cmp byte [esp], 40d
jnge irq_basic_end
mov al, 0xa0
out 0x20, al
irq_basic_end:
pop eax
sti
iret
idt:
dw isr_0, 8, 0x8e00, 0x0000
dw isr_1, 8, 0x8e00, 0x0000
dw isr_2, 8, 0x8e00, 0x0000
dw isr_3, 8, 0x8e00, 0x0000
dw isr_4, 8, 0x8e00, 0x0000
dw isr_5, 8, 0x8e00, 0x0000
dw isr_6, 8, 0x8e00, 0x0000
dw isr_7, 8, 0x8e00, 0x0000
dw isr_8, 8, 0x8e00, 0x0000
dw isr_9, 8, 0x8e00, 0x0000
dw isr_10, 8, 0x8e00, 0x0000
dw isr_11, 8, 0x8e00, 0x0000
dw isr_12, 8, 0x8e00, 0x0000
dw isr_13, 8, 0x8e00, 0x0000
dw isr_14, 8, 0x8e00, 0x0000
dw isr_15, 8, 0x8e00, 0x0000
dw isr_16, 8, 0x8e00, 0x0000
dw isr_17, 8, 0x8e00, 0x0000
dw isr_18, 8, 0x8e00, 0x0000
dw isr_19, 8, 0x8e00, 0x0000
dw isr_20, 8, 0x8e00, 0x0000
dw isr_21, 8, 0x8e00, 0x0000
dw isr_22, 8, 0x8e00, 0x0000
dw isr_23, 8, 0x8e00, 0x0000
dw isr_24, 8, 0x8e00, 0x0000
dw isr_25, 8, 0x8e00, 0x0000
dw isr_26, 8, 0x8e00, 0x0000
dw isr_27, 8, 0x8e00, 0x0000
dw isr_28, 8, 0x8e00, 0x0000
dw isr_29, 8, 0x8e00, 0x0000
dw isr_30, 8, 0x8e00, 0x0000
dw isr_31, 8, 0x8e00, 0x0000
dw isr_32, 8, 0x8e00, 0x0000
dw isr_33, 8, 0x8e00, 0x0000
dw isr_34, 8, 0x8e00, 0x0000
dw isr_35, 8, 0x8e00, 0x0000
dw isr_36, 8, 0x8e00, 0x0000
dw isr_37, 8, 0x8e00, 0x0000
dw isr_38, 8, 0x8e00, 0x0000
dw isr_39, 8, 0x8e00, 0x0000
dw isr_40, 8, 0x8e00, 0x0000
dw isr_41, 8, 0x8e00, 0x0000
dw isr_42, 8, 0x8e00, 0x0000
dw isr_43, 8, 0x8e00, 0x0000
dw isr_44, 8, 0x8e00, 0x0000
dw isr_45, 8, 0x8e00, 0x0000
dw isr_46, 8, 0x8e00, 0x0000
dw isr_47, 8, 0x8e00, 0x0000
dw isr_48, 8, 0x8e00, 0x0000
idtr:
idt_size_in_bytes : dw idtr - idt
idt_base_address : dd idt
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/linker.ld
================================================
/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */
SECTIONS
{
.text 0x09000 :
{
code = .; _code = .; __code = .;
*(.text)
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
}
end = .; _end = .; __end = .;
}
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/main.c
================================================
volatile unsigned char *video = 0xB8000;
int nextTextPos = 0;
int currLine = 0;
void print( char * );
void println();
void printi( int );
void kernel_main()
{
print( "Welcome to 539kernel!" );
println();
print( "We are now in Protected-mode" );
println();
printi( 539 );
println();
while( 1 );
}
void interrupt_handler( int interrupt_number )
{
println();
print( "Interrupt Received " );
printi( interrupt_number );
}
void print( char *str )
{
int currCharLocationInVidMem, currColorLocationInVidMem;
while ( *str != '\0' )
{
currCharLocationInVidMem = nextTextPos * 2;
currColorLocationInVidMem = currCharLocationInVidMem + 1;
video[ currCharLocationInVidMem ] = *str;
video[ currColorLocationInVidMem ] = 15;
nextTextPos++;
str++;
}
}
void println()
{
nextTextPos = ++currLine * 80;
}
void printi( int number )
{
char* digitToStr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if ( number >= 0 && number <= 9 )
{
print( digitToStr[ number ] );
return;
}
else
{
int remaining = number % 10;
number = number / 10;
printi( number );
printi( remaining );
}
}
================================================
FILE: evolution_by_versions/03_539kernel_progenitor/starter.asm
================================================
bits 16
extern kernel_main
extern interrupt_handler
start:
mov ax, cs
mov ds, ax
call load_gdt
call init_video_mode
call enter_protected_mode
call setup_interrupts
call 08h:start_kernel
load_gdt:
cli
lgdt [gdtr - start]
ret
enter_protected_mode:
mov eax, cr0
or eax, 1
mov cr0, eax
ret
init_video_mode:
mov ah, 0h
mov al, 03h
int 10h
mov ah, 01h
mov cx, 2000h
int 10h
ret
setup_interrupts:
call remap_pic
call load_idt
ret
remap_pic:
mov al, 11h
send_init_cmd_to_pic_master:
out 0x20, al
send_init_cmd_to_pic_slave:
out 0xa0, al
; ... ;
make_irq_starts_from_intr_32_in_pic_master:
mov al, 32d
out 0x21, al
make_irq_starts_from_intr_40_in_pic_slave:
mov al, 40d
out 0xa1, al
; ... ;
tell_pic_master_where_pic_slave_is_connected:
mov al, 04h
out 0x21, al
tell_pic_slave_where_pic_master_is_connected:
mov al, 02h
out 0xa1, al
; ... ;
mov al, 01h
tell_pic_master_the_arch_is_x86:
out 0x21, al
tell_pic_slave_the_arch_is_x86:
out 0xa1, al
; ... ;
mov al, 0h
make_pic_master_enables_all_irqs:
out 0x21, al
make_pic_slave_enables_all_irqs:
out 0xa1, al
; ... ;
ret
load_idt:
lidt [idtr - start]
ret
bits 32
start_kernel:
mov eax, 10h
mov ds, eax
mov ss, eax
mov eax, 0h
mov es, eax
mov fs, eax
mov gs, eax
sti
call kernel_main
%include "gdt.asm"
%include "idt.asm"
================================================
FILE: evolution_by_versions/04_539kernel_version_t/Makefile
================================================
ASM = nasm
CC = gcc
BOOTSTRAP_FILE = bootstrap.asm
INIT_KERNEL_FILES = starter.asm
KERNEL_FILES = main.c
KERNEL_FLAGS = -Wall -m32 -c -ffreestanding -fno-asynchronous-unwind-tables -fno-pie
KERNEL_OBJECT = -o kernel.elf
build: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
$(CC) $(KERNEL_FLAGS) screen.c -o screen.elf
$(CC) $(KERNEL_FLAGS) process.c -o process.elf
$(CC) $(KERNEL_FLAGS) scheduler.c -o scheduler.elf
ld -melf_i386 -Tlinker.ld starter.o kernel.elf screen.elf process.elf scheduler.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=8
dd seek=9 conv=sync if=/dev/zero of=kernel.img bs=512 count=2046
qemu-system-x86_64 -s kernel.img
================================================
FILE: evolution_by_versions/04_539kernel_version_t/bootstrap.asm
================================================
start:
mov ax, 07C0h
mov ds, ax
mov si, title_string
call print_string
mov si, message_string
call print_string
call load_kernel_from_disk
jmp 0900h:0000
load_kernel_from_disk:
mov ax, [curr_sector_to_load]
sub ax, 2
mov bx, 512d
mul bx
mov bx, ax
mov ax, 0900h
mov es, ax
mov ah, 02h
mov al, 1h
mov ch, 0h
mov cl, [curr_sector_to_load]
mov dh, 0h
mov dl, 80h
int 13h
jc kernel_load_error
sub byte [number_of_sectors_to_load], 1
add byte [curr_sector_to_load], 1
cmp byte [number_of_sectors_to_load], 0
jne load_kernel_from_disk
ret
kernel_load_error:
mov si, load_error_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; Reading current cursor position
mov ah, 03h
mov bh, 0
int 10h
; Move the cursor to the beginning
mov ah, 02h
mov dl, 0
int 10h
ret
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
number_of_sectors_to_load db 10d
curr_sector_to_load db 2d
times 510-($-$$) db 0
dw 0xAA55
================================================
FILE: evolution_by_versions/04_539kernel_version_t/gdt.asm
================================================
gdt:
null_descriptor : dw 0, 0, 0, 0
kernel_code_descriptor : dw 0xffff, 0x0000, 0x9a00, 0x00cf
kernel_data_descriptor : dw 0xffff, 0x0000, 0x9200, 0x00cf
userspace_code_descriptor : dw 0xffff, 0x0000, 0xfa00, 0x00cf
userspace_data_descriptor : dw 0xffff, 0x0000, 0xf200, 0x00cf
tss_descriptor : dw tss + 3, tss, 0x8900, 0x0000
gdtr:
gdt_size_in_bytes : dw ( 6 * 8 )
gdt_base_address : dd gdt
================================================
FILE: evolution_by_versions/04_539kernel_version_t/idt.asm
================================================
isr_0:
cli
push 0
jmp isr_basic
isr_1:
cli
push 1
jmp isr_basic
isr_2:
cli
push 2
jmp isr_basic
isr_3:
cli
push 3
jmp isr_basic
isr_4:
cli
push 4
jmp isr_basic
isr_5:
cli
push 5
jmp isr_basic
isr_6:
cli
push 6
jmp isr_basic
isr_7:
cli
push 7
jmp isr_basic
isr_8:
cli
push 8
jmp isr_basic
isr_9:
cli
push 9
jmp isr_basic
isr_10:
cli
push 10
jmp isr_basic
isr_11:
cli
push 11
jmp isr_basic
isr_12:
cli
push 12
jmp isr_basic
isr_13:
cli
push 13
jmp isr_basic
isr_14:
cli
push 14
jmp isr_basic
isr_15:
cli
push 15
jmp isr_basic
isr_16:
cli
push 16
jmp isr_basic
isr_17:
cli
push 17
jmp isr_basic
isr_18:
cli
push 18
jmp isr_basic
isr_19:
cli
push 19
jmp isr_basic
isr_20:
cli
push 20
jmp isr_basic
isr_21:
cli
push 21
jmp isr_basic
isr_22:
cli
push 22
jmp isr_basic
isr_23:
cli
push 23
jmp isr_basic
isr_24:
cli
push 24
jmp isr_basic
isr_25:
cli
push 25
jmp isr_basic
isr_26:
cli
push 26
jmp isr_basic
isr_27:
cli
push 27
jmp isr_basic
isr_28:
cli
push 28
jmp isr_basic
isr_29:
cli
push 29
jmp isr_basic
isr_30:
cli
push 30
jmp isr_basic
isr_31:
cli
push 31
jmp isr_basic
isr_32:
; Part 1
cli ; Step 1
pusha ; Step 2
; Step 3
mov eax, [esp + 32]
push eax
call scheduler ; Step 4
; ... ;
; Part 2
; Step 5
mov al, 0x20
out 0x20, al
; Step 6
add esp, 40d
push run_next_process
iret ; Step 7
isr_33:
cli
push 33
jmp irq_basic
isr_34:
cli
push 34
jmp irq_basic
isr_35:
cli
push 35
jmp irq_basic
isr_36:
cli
push 36
jmp irq_basic
isr_37:
cli
push 37
jmp irq_basic
isr_38:
cli
push 38
jmp irq_basic
isr_39:
cli
push 39
jmp irq_basic
isr_40:
cli
push 40
jmp irq_basic
isr_41:
cli
push 41
jmp irq_basic
isr_42:
cli
push 42
jmp irq_basic
isr_43:
cli
push 43
jmp irq_basic
isr_44:
cli
push 44
jmp irq_basic
isr_45:
cli
push 45
jmp irq_basic
isr_46:
cli
push 46
jmp irq_basic
isr_47:
cli
push 47
jmp irq_basic
isr_48:
cli
push 48
jmp irq_basic
isr_basic:
call interrupt_handler
pop eax
sti
iret
irq_basic:
call interrupt_handler
mov al, 0x20
out 0x20, al
cmp byte [esp], 40d
jnge irq_basic_end
mov al, 0xa0
out 0x20, al
irq_basic_end:
pop eax
sti
iret
idt:
dw isr_0, 8, 0x8e00, 0x0000
dw isr_1, 8, 0x8e00, 0x0000
dw isr_2, 8, 0x8e00, 0x0000
dw isr_3, 8, 0x8e00, 0x0000
dw isr_4, 8, 0x8e00, 0x0000
dw isr_5, 8, 0x8e00, 0x0000
dw isr_6, 8, 0x8e00, 0x0000
dw isr_7, 8, 0x8e00, 0x0000
dw isr_8, 8, 0x8e00, 0x0000
dw isr_9, 8, 0x8e00, 0x0000
dw isr_10, 8, 0x8e00, 0x0000
dw isr_11, 8, 0x8e00, 0x0000
dw isr_12, 8, 0x8e00, 0x0000
dw isr_13, 8, 0x8e00, 0x0000
dw isr_14, 8, 0x8e00, 0x0000
dw isr_15, 8, 0x8e00, 0x0000
dw isr_16, 8, 0x8e00, 0x0000
dw isr_17, 8, 0x8e00, 0x0000
dw isr_18, 8, 0x8e00, 0x0000
dw isr_19, 8, 0x8e00, 0x0000
dw isr_20, 8, 0x8e00, 0x0000
dw isr_21, 8, 0x8e00, 0x0000
dw isr_22, 8, 0x8e00, 0x0000
dw isr_23, 8, 0x8e00, 0x0000
dw isr_24, 8, 0x8e00, 0x0000
dw isr_25, 8, 0x8e00, 0x0000
dw isr_26, 8, 0x8e00, 0x0000
dw isr_27, 8, 0x8e00, 0x0000
dw isr_28, 8, 0x8e00, 0x0000
dw isr_29, 8, 0x8e00, 0x0000
dw isr_30, 8, 0x8e00, 0x0000
dw isr_31, 8, 0x8e00, 0x0000
dw isr_32, 8, 0x8e00, 0x0000
dw isr_33, 8, 0x8e00, 0x0000
dw isr_34, 8, 0x8e00, 0x0000
dw isr_35, 8, 0x8e00, 0x0000
dw isr_36, 8, 0x8e00, 0x0000
dw isr_37, 8, 0x8e00, 0x0000
dw isr_38, 8, 0x8e00, 0x0000
dw isr_39, 8, 0x8e00, 0x0000
dw isr_40, 8, 0x8e00, 0x0000
dw isr_41, 8, 0x8e00, 0x0000
dw isr_42, 8, 0x8e00, 0x0000
dw isr_43, 8, 0x8e00, 0x0000
dw isr_44, 8, 0x8e00, 0x0000
dw isr_45, 8, 0x8e00, 0x0000
dw isr_46, 8, 0x8e00, 0x0000
dw isr_47, 8, 0x8e00, 0x0000
dw isr_48, 8, 0x8e00, 0x0000
idtr:
idt_size_in_bytes : dw idtr - idt
idt_base_address : dd idt
================================================
FILE: evolution_by_versions/04_539kernel_version_t/linker.ld
================================================
/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */
SECTIONS
{
.text 0x09000 :
{
code = .; _code = .; __code = .;
*(.text)
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
}
end = .; _end = .; __end = .;
}
================================================
FILE: evolution_by_versions/04_539kernel_version_t/main.c
================================================
#include "screen.h"
#include "scheduler.h"
void processA();
void processB();
void processC();
void processD();
void kernel_main()
{
process_t p1, p2, p3, p4;
screen_init();
process_init();
scheduler_init();
print( "Welcome to 539kernel!" );
println();
print( "We are now in Protected-mode" );
println();
printi( 539 );
println();
process_create( &processA, &p1 );
process_create( &processB, &p2 );
process_create( &processC, &p3 );
process_create( &processD, &p4 );
while( 1 );
}
void interrupt_handler( int interrupt_number )
{
println();
print( "Interrupt Received " );
printi( interrupt_number );
}
void processA()
{
print( "Process A," );
while ( 1 )
asm( "mov $5390, %eax" );
}
void processB()
{
print( "Process B," );
while ( 1 )
asm( "mov $5391, %eax" );
}
void processC()
{
print( "Process C," );
while ( 1 )
asm( "mov $5392, %eax" );
}
void processD()
{
print( "Process D," );
while ( 1 )
asm( "mov $5393, %eax" );
}
================================================
FILE: evolution_by_versions/04_539kernel_version_t/process.c
================================================
#include "process.h"
void process_init()
{
processes_count = 0;
curr_pid = 0;
}
void process_create( int *base_address, process_t *process )
{
process->pid = curr_pid++;
process->context.eax = 0;
process->context.ecx = 0;
process->context.edx = 0;
process->context.ebx = 0;
process->context.esp = 0;
process->context.ebp = 0;
process->context.esi = 0;
process->context.edi = 0;
process->context.eip = base_address;
process->state = READY;
process->base_address = base_address;
processes[ process->pid ] = process;
processes_count++;
}
================================================
FILE: evolution_by_versions/04_539kernel_version_t/process.h
================================================
typedef enum process_state { READY, RUNNING } process_state_t;
typedef struct process_context
{
int eax, ecx, edx, ebx, esp, ebp, esi, edi, eip;
} process_context_t;
typedef struct process
{
int pid;
process_context_t context;
process_state_t state;
int *base_address;
} process_t;
process_t *processes[ 15 ];
int processes_count, curr_pid;
void process_init();
void process_create( int *, process_t * );
================================================
FILE: evolution_by_versions/04_539kernel_version_t/scheduler.c
================================================
#include "scheduler.h"
void scheduler_init()
{
next_sch_pid = 0;
curr_sch_pid = 0;
}
process_t *get_next_process()
{
process_t *next_process = processes[ next_sch_pid ];
curr_sch_pid = next_sch_pid;
next_sch_pid++;
next_sch_pid = next_sch_pid % processes_count;
return next_process;
}
void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax )
{
process_t *curr_process;
print( " EAX = " ); // For Testing Purpose
printi( eax ); // For Testing Purpose
// ... //
// PART 1
curr_process = processes[ curr_sch_pid ];
next_process = get_next_process();
// ... //
// PART 2
if ( curr_process->state == RUNNING )
{
curr_process->context.eax = eax;
curr_process->context.ecx = ecx;
curr_process->context.edx = edx;
curr_process->context.ebx = ebx;
curr_process->context.esp = esp;
curr_process->context.ebp = ebp;
curr_process->context.esi = esi;
curr_process->context.edi = edi;
curr_process->context.eip = eip;
}
curr_process->state = READY;
// ... //
// PART 3
asm( " mov %0, %%eax; \
mov %0, %%ecx; \
mov %0, %%edx; \
mov %0, %%ebx; \
mov %0, %%esi; \
mov %0, %%edi;"
: : "r" ( next_process->context.eax ), "r" ( next_process->context.ecx ), "r" ( next_process->context.edx ), "r" ( next_process->context.ebx ),
"r" ( next_process->context.esi ), "r" ( next_process->context.edi ) );
next_process->state = RUNNING;
}
void run_next_process()
{
asm( " sti; \
jmp *%0" : : "r" ( next_process->context.eip ) );
}
================================================
FILE: evolution_by_versions/04_539kernel_version_t/scheduler.h
================================================
#include "process.h"
int next_sch_pid, curr_sch_pid;
process_t *next_process;
void scheduler_init();
process_t *get_next_process();
void scheduler( int, int, int, int, int, int, int, int, int );
void run_next_process();
================================================
FILE: evolution_by_versions/04_539kernel_version_t/screen.c
================================================
#include "screen.h"
void screen_init()
{
video = 0xB8000;
nextTextPos = 0;
currLine = 0;
}
void print( char *str )
{
int currCharLocationInVidMem, currColorLocationInVidMem;
while ( *str != '\0' )
{
currCharLocationInVidMem = nextTextPos * 2;
currColorLocationInVidMem = currCharLocationInVidMem + 1;
video[ currCharLocationInVidMem ] = *str;
video[ currColorLocationInVidMem ] = 15;
nextTextPos++;
str++;
}
}
void println()
{
nextTextPos = ++currLine * 80;
}
void printi( int number )
{
char* digitToStr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if ( number >= 0 && number <= 9 )
{
print( digitToStr[ number ] );
return;
}
else
{
int remaining = number % 10;
number = number / 10;
printi( number );
printi( remaining );
}
}
================================================
FILE: evolution_by_versions/04_539kernel_version_t/screen.h
================================================
volatile unsigned char *video;
int nextTextPos;
int currLine;
void screen_init();
void print( char * );
void println();
void printi( int );
================================================
FILE: evolution_by_versions/04_539kernel_version_t/starter.asm
================================================
bits 16
extern kernel_main
extern interrupt_handler
extern scheduler
extern run_next_process
start:
mov ax, cs
mov ds, ax
call load_gdt
call init_video_mode
call enter_protected_mode
call setup_interrupts
call load_task_register
call 08h:start_kernel
load_gdt:
cli
lgdt [gdtr - start]
ret
enter_protected_mode:
mov eax, cr0
or eax, 1
mov cr0, eax
ret
init_video_mode:
mov ah, 0h
mov al, 03h
int 10h
mov ah, 01h
mov cx, 2000h
int 10h
ret
setup_interrupts:
call remap_pic
call load_idt
ret
remap_pic:
mov al, 11h
send_init_cmd_to_pic_master:
out 0x20, al
send_init_cmd_to_pic_slave:
out 0xa0, al
; ... ;
make_irq_starts_from_intr_32_in_pic_master:
mov al, 32d
out 0x21, al
make_irq_starts_from_intr_40_in_pic_slave:
mov al, 40d
out 0xa1, al
; ... ;
tell_pic_master_where_pic_slave_is_connected:
mov al, 04h
out 0x21, al
tell_pic_slave_where_pic_master_is_connected:
mov al, 02h
out 0xa1, al
; ... ;
mov al, 01h
tell_pic_master_the_arch_is_x86:
out 0x21, al
tell_pic_slave_the_arch_is_x86:
out 0xa1, al
; ... ;
mov al, 0h
make_pic_master_enables_all_irqs:
out 0x21, al
make_pic_slave_enables_all_irqs:
out 0xa1, al
; ... ;
ret
load_idt:
lidt [idtr - start]
ret
load_task_register:
mov ax, 40d
ltr ax
ret
bits 32
start_kernel:
mov eax, 10h
mov ds, eax
mov ss, eax
mov eax, 0h
mov es, eax
mov fs, eax
mov gs, eax
sti
call kernel_main
%include "gdt.asm"
%include "idt.asm"
tss:
dd 0
================================================
FILE: evolution_by_versions/05_539kernel_version_g/Makefile
================================================
ASM = nasm
CC = gcc
BOOTSTRAP_FILE = bootstrap.asm
SIMPLE_KERNEL = simple_kernel.asm
INIT_KERNEL_FILES = starter.asm
KERNEL_FILES = main.c
KERNEL_FLAGS = -Wall -m32 -c -ffreestanding -fno-asynchronous-unwind-tables -fno-pie
KERNEL_OBJECT = -o kernel.elf
build: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
$(CC) $(KERNEL_FLAGS) screen.c -o screen.elf
$(CC) $(KERNEL_FLAGS) process.c -o process.elf
$(CC) $(KERNEL_FLAGS) scheduler.c -o scheduler.elf
$(CC) $(KERNEL_FLAGS) heap.c -o heap.elf
$(CC) $(KERNEL_FLAGS) paging.c -o paging.elf
ld -melf_i386 -Tlinker.ld starter.o kernel.elf screen.elf process.elf scheduler.elf heap.elf paging.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=8
dd seek=9 conv=sync if=/dev/zero of=kernel.img bs=512 count=2046
qemu-system-x86_64 -s kernel.img
================================================
FILE: evolution_by_versions/05_539kernel_version_g/bootstrap.asm
================================================
start:
mov ax, 07C0h
mov ds, ax
mov si, title_string
call print_string
mov si, message_string
call print_string
call load_kernel_from_disk
jmp 0900h:0000
load_kernel_from_disk:
mov ax, [curr_sector_to_load]
sub ax, 2
mov bx, 512d
mul bx
mov bx, ax
mov ax, 0900h
mov es, ax
mov ah, 02h
mov al, 1h
mov ch, 0h
mov cl, [curr_sector_to_load]
mov dh, 0h
mov dl, 80h
int 13h
jc kernel_load_error
sub byte [number_of_sectors_to_load], 1
add byte [curr_sector_to_load], 1
cmp byte [number_of_sectors_to_load], 0
jne load_kernel_from_disk
ret
kernel_load_error:
mov si, load_error_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; Reading current cursor position
mov ah, 03h
mov bh, 0
int 10h
; Move the cursor to the beginning
mov ah, 02h
mov dl, 0
int 10h
ret
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
number_of_sectors_to_load db 10d
curr_sector_to_load db 2d
times 510-($-$$) db 0
dw 0xAA55
================================================
FILE: evolution_by_versions/05_539kernel_version_g/gdt.asm
================================================
gdt:
null_descriptor : dw 0, 0, 0, 0
kernel_code_descriptor : dw 0xffff, 0x0000, 0x9a00, 0x00cf
kernel_data_descriptor : dw 0xffff, 0x0000, 0x9200, 0x00cf
userspace_code_descriptor : dw 0xffff, 0x0000, 0xfa00, 0x00cf
userspace_data_descriptor : dw 0xffff, 0x0000, 0xf200, 0x00cf
tss_descriptor : dw tss + 3, tss, 0x8900, 0x0000
gdtr:
gdt_size_in_bytes : dw ( 6 * 8 )
gdt_base_address : dd gdt
================================================
FILE: evolution_by_versions/05_539kernel_version_g/heap.c
================================================
#include "heap.h"
void heap_init()
{
heap_base = 0x100000;
}
int kalloc( int bytes )
{
unsigned int new_object_address = heap_base;
heap_base += bytes;
return new_object_address;
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/heap.h
================================================
unsigned int heap_base;
void heap_init();
int kalloc( int );
================================================
FILE: evolution_by_versions/05_539kernel_version_g/idt.asm
================================================
isr_0:
cli
push 0
jmp isr_basic
isr_1:
cli
push 1
jmp isr_basic
isr_2:
cli
push 2
jmp isr_basic
isr_3:
cli
push 3
jmp isr_basic
isr_4:
cli
push 4
jmp isr_basic
isr_5:
cli
push 5
jmp isr_basic
isr_6:
cli
push 6
jmp isr_basic
isr_7:
cli
push 7
jmp isr_basic
isr_8:
cli
push 8
jmp isr_basic
isr_9:
cli
push 9
jmp isr_basic
isr_10:
cli
push 10
jmp isr_basic
isr_11:
cli
push 11
jmp isr_basic
isr_12:
cli
push 12
jmp isr_basic
isr_13:
cli
push 13
jmp isr_basic
isr_14:
cli
push 14
jmp isr_basic
isr_15:
cli
push 15
jmp isr_basic
isr_16:
cli
push 16
jmp isr_basic
isr_17:
cli
push 17
jmp isr_basic
isr_18:
cli
push 18
jmp isr_basic
isr_19:
cli
push 19
jmp isr_basic
isr_20:
cli
push 20
jmp isr_basic
isr_21:
cli
push 21
jmp isr_basic
isr_22:
cli
push 22
jmp isr_basic
isr_23:
cli
push 23
jmp isr_basic
isr_24:
cli
push 24
jmp isr_basic
isr_25:
cli
push 25
jmp isr_basic
isr_26:
cli
push 26
jmp isr_basic
isr_27:
cli
push 27
jmp isr_basic
isr_28:
cli
push 28
jmp isr_basic
isr_29:
cli
push 29
jmp isr_basic
isr_30:
cli
push 30
jmp isr_basic
isr_31:
cli
push 31
jmp isr_basic
isr_32:
; Part 1
cli ; Step 1
pusha ; Step 2
; Step 3
mov eax, [esp + 32]
push eax
call scheduler ; Step 4
; ... ;
; Part 2
; Step 5
mov al, 0x20
out 0x20, al
; Step 6
add esp, 40d
push run_next_process
iret ; Step 7
isr_33:
cli
push 33
jmp irq_basic
isr_34:
cli
push 34
jmp irq_basic
isr_35:
cli
push 35
jmp irq_basic
isr_36:
cli
push 36
jmp irq_basic
isr_37:
cli
push 37
jmp irq_basic
isr_38:
cli
push 38
jmp irq_basic
isr_39:
cli
push 39
jmp irq_basic
isr_40:
cli
push 40
jmp irq_basic
isr_41:
cli
push 41
jmp irq_basic
isr_42:
cli
push 42
jmp irq_basic
isr_43:
cli
push 43
jmp irq_basic
isr_44:
cli
push 44
jmp irq_basic
isr_45:
cli
push 45
jmp irq_basic
isr_46:
cli
push 46
jmp irq_basic
isr_47:
cli
push 47
jmp irq_basic
isr_48:
cli
push 48
jmp irq_basic
isr_basic:
call interrupt_handler
pop eax
sti
iret
irq_basic:
call interrupt_handler
mov al, 0x20
out 0x20, al
cmp byte [esp], 40d
jnge irq_basic_end
mov al, 0xa0
out 0x20, al
irq_basic_end:
pop eax
sti
iret
idt:
dw isr_0, 8, 0x8e00, 0x0000
dw isr_1, 8, 0x8e00, 0x0000
dw isr_2, 8, 0x8e00, 0x0000
dw isr_3, 8, 0x8e00, 0x0000
dw isr_4, 8, 0x8e00, 0x0000
dw isr_5, 8, 0x8e00, 0x0000
dw isr_6, 8, 0x8e00, 0x0000
dw isr_7, 8, 0x8e00, 0x0000
dw isr_8, 8, 0x8e00, 0x0000
dw isr_9, 8, 0x8e00, 0x0000
dw isr_10, 8, 0x8e00, 0x0000
dw isr_11, 8, 0x8e00, 0x0000
dw isr_12, 8, 0x8e00, 0x0000
dw isr_13, 8, 0x8e00, 0x0000
dw isr_14, 8, 0x8e00, 0x0000
dw isr_15, 8, 0x8e00, 0x0000
dw isr_16, 8, 0x8e00, 0x0000
dw isr_17, 8, 0x8e00, 0x0000
dw isr_18, 8, 0x8e00, 0x0000
dw isr_19, 8, 0x8e00, 0x0000
dw isr_20, 8, 0x8e00, 0x0000
dw isr_21, 8, 0x8e00, 0x0000
dw isr_22, 8, 0x8e00, 0x0000
dw isr_23, 8, 0x8e00, 0x0000
dw isr_24, 8, 0x8e00, 0x0000
dw isr_25, 8, 0x8e00, 0x0000
dw isr_26, 8, 0x8e00, 0x0000
dw isr_27, 8, 0x8e00, 0x0000
dw isr_28, 8, 0x8e00, 0x0000
dw isr_29, 8, 0x8e00, 0x0000
dw isr_30, 8, 0x8e00, 0x0000
dw isr_31, 8, 0x8e00, 0x0000
dw isr_32, 8, 0x8e00, 0x0000
dw isr_33, 8, 0x8e00, 0x0000
dw isr_34, 8, 0x8e00, 0x0000
dw isr_35, 8, 0x8e00, 0x0000
dw isr_36, 8, 0x8e00, 0x0000
dw isr_37, 8, 0x8e00, 0x0000
dw isr_38, 8, 0x8e00, 0x0000
dw isr_39, 8, 0x8e00, 0x0000
dw isr_40, 8, 0x8e00, 0x0000
dw isr_41, 8, 0x8e00, 0x0000
dw isr_42, 8, 0x8e00, 0x0000
dw isr_43, 8, 0x8e00, 0x0000
dw isr_44, 8, 0x8e00, 0x0000
dw isr_45, 8, 0x8e00, 0x0000
dw isr_46, 8, 0x8e00, 0x0000
dw isr_47, 8, 0x8e00, 0x0000
dw isr_48, 8, 0x8e00, 0x0000
idtr:
idt_size_in_bytes : dw idtr - idt
idt_base_address : dd idt
================================================
FILE: evolution_by_versions/05_539kernel_version_g/linker.ld
================================================
/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */
SECTIONS
{
.text 0x09000 :
{
code = .; _code = .; __code = .;
*(.text)
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
}
end = .; _end = .; __end = .;
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/main.c
================================================
#include "screen.h"
#include "scheduler.h"
#include "heap.h"
void processA();
void processB();
void processC();
void processD();
void kernel_main()
{
heap_init();
paging_init();
screen_init();
process_init();
scheduler_init();
print( "Welcome to 539kernel!" );
println();
print( "We are now in Protected-mode" );
println();
printi( 539 );
println();
process_create( &processA );
process_create( &processB );
process_create( &processC );
process_create( &processD );
while( 1 );
}
void interrupt_handler( int interrupt_number )
{
println();
print( "Interrupt Received " );
printi( interrupt_number );
}
void processA()
{
print( "Process A," );
while ( 1 )
asm( "mov $5390, %eax" );
}
void processB()
{
print( "Process B," );
while ( 1 )
asm( "mov $5391, %eax" );
}
void processC()
{
print( "Process C," );
while ( 1 )
asm( "mov $5392, %eax" );
}
void processD()
{
print( "Process D," );
while ( 1 )
asm( "mov $5393, %eax" );
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/paging.c
================================================
#include "paging.h"
int create_page_entry( int base_address, char present, char writable, char privilege_level, char cache_enabled, char write_through_cache, char accessed, char page_size, char dirty )
{
int entry = 0;
entry |= present;
entry |= writable << 1;
entry |= privilege_level << 2;
entry |= write_through_cache << 3;
entry |= cache_enabled << 4;
entry |= accessed << 5;
entry |= dirty << 6;
entry |= page_size << 7;
return base_address | entry;
}
void paging_init()
{
// PART 1:
unsigned int curr_page_frame = 0;
page_directory = kalloc( 4 * 1024 );
for ( int currPDE = 0; currPDE < PDE_NUM; currPDE++ )
{
unsigned int *pagetable = kalloc( 4 * PTE_NUM );
for ( int currPTE = 0; currPTE < PTE_NUM; currPTE++, curr_page_frame++ )
pagetable[ currPTE ] = create_page_entry( curr_page_frame * 4096, 1, 0, 0, 1, 1, 0, 0, 0 );
page_directory[ currPDE ] = create_page_entry( pagetable, 1, 0, 0, 1, 1, 0, 0, 0 );
}
// ... //
// PART 2
load_page_directory();
enable_paging();
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/paging.h
================================================
#define PDE_NUM 3
#define PTE_NUM 1024
extern void load_page_directory();
extern void enable_paging();
unsigned int *page_directory;
void paging_init();
int create_page_entry( int, char, char, char, char, char, char, char, char );
================================================
FILE: evolution_by_versions/05_539kernel_version_g/process.c
================================================
#include "process.h"
void process_init()
{
processes_count = 0;
curr_pid = 0;
}
process_t *process_create( int *base_address )
{
process_t *process = kalloc( sizeof( process_t ) );
process->pid = curr_pid++;
process->context.eax = 0;
process->context.ecx = 0;
process->context.edx = 0;
process->context.ebx = 0;
process->context.esp = 0;
process->context.ebp = 0;
process->context.esi = 0;
process->context.edi = 0;
process->context.eip = base_address;
process->state = READY;
process->base_address = base_address;
processes[ process->pid ] = process;
processes_count++;
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/process.h
================================================
typedef enum process_state { READY, RUNNING } process_state_t;
typedef struct process_context
{
int eax, ecx, edx, ebx, esp, ebp, esi, edi, eip;
} process_context_t;
typedef struct process
{
int pid;
process_context_t context;
process_state_t state;
int *base_address;
} process_t;
process_t *processes[ 15 ];
int processes_count, curr_pid;
void process_init();
process_t *process_create( int * );
================================================
FILE: evolution_by_versions/05_539kernel_version_g/scheduler.c
================================================
#include "scheduler.h"
void scheduler_init()
{
next_sch_pid = 0;
curr_sch_pid = 0;
}
process_t *get_next_process()
{
process_t *next_process = processes[ next_sch_pid ];
curr_sch_pid = next_sch_pid;
next_sch_pid++;
next_sch_pid = next_sch_pid % processes_count;
return next_process;
}
void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax )
{
process_t *curr_process;
print( " EAX = " ); // For Testing Purpose
printi( eax ); // For Testing Purpose
// ... //
// PART 1
curr_process = processes[ curr_sch_pid ];
next_process = get_next_process();
// ... //
// PART 2
if ( curr_process->state == RUNNING )
{
curr_process->context.eax = eax;
curr_process->context.ecx = ecx;
curr_process->context.edx = edx;
curr_process->context.ebx = ebx;
curr_process->context.esp = esp;
curr_process->context.ebp = ebp;
curr_process->context.esi = esi;
curr_process->context.edi = edi;
curr_process->context.eip = eip;
}
curr_process->state = READY;
// ... //
// PART 3
asm( " mov %0, %%eax; \
mov %0, %%ecx; \
mov %0, %%edx; \
mov %0, %%ebx; \
mov %0, %%esi; \
mov %0, %%edi;"
: : "r" ( next_process->context.eax ), "r" ( next_process->context.ecx ), "r" ( next_process->context.edx ), "r" ( next_process->context.ebx ),
"r" ( next_process->context.esi ), "r" ( next_process->context.edi ) );
next_process->state = RUNNING;
}
void run_next_process()
{
asm( " sti; \
jmp *%0" : : "r" ( next_process->context.eip ) );
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/scheduler.h
================================================
#include "process.h"
int next_sch_pid, curr_sch_pid;
process_t *next_process;
void scheduler_init();
process_t *get_next_process();
void scheduler( int, int, int, int, int, int, int, int, int );
void run_next_process();
================================================
FILE: evolution_by_versions/05_539kernel_version_g/screen.c
================================================
#include "screen.h"
void screen_init()
{
video = 0xB8000;
nextTextPos = 0;
currLine = 0;
}
void print( char *str )
{
int currCharLocationInVidMem, currColorLocationInVidMem;
while ( *str != '\0' )
{
currCharLocationInVidMem = nextTextPos * 2;
currColorLocationInVidMem = currCharLocationInVidMem + 1;
video[ currCharLocationInVidMem ] = *str;
video[ currColorLocationInVidMem ] = 15;
nextTextPos++;
str++;
}
}
void println()
{
nextTextPos = ++currLine * 80;
}
void printi( int number )
{
char* digitToStr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if ( number >= 0 && number <= 9 )
{
print( digitToStr[ number ] );
return;
}
else
{
int remaining = number % 10;
number = number / 10;
printi( number );
printi( remaining );
}
}
================================================
FILE: evolution_by_versions/05_539kernel_version_g/screen.h
================================================
volatile unsigned char *video;
int nextTextPos;
int currLine;
void screen_init();
void print( char * );
void println();
void printi( int );
================================================
FILE: evolution_by_versions/05_539kernel_version_g/starter.asm
================================================
bits 16
extern kernel_main
extern interrupt_handler
extern scheduler
extern run_next_process
extern page_directory
global load_page_directory
global enable_paging
start:
mov ax, cs
mov ds, ax
call load_gdt
call init_video_mode
call enter_protected_mode
call setup_interrupts
call load_task_register
call 08h:start_kernel
load_gdt:
cli
lgdt [gdtr - start]
ret
enter_protected_mode:
mov eax, cr0
or eax, 1
mov cr0, eax
ret
init_video_mode:
mov ah, 0h
mov al, 03h
int 10h
mov ah, 01h
mov cx, 2000h
int 10h
ret
setup_interrupts:
call remap_pic
call load_idt
ret
remap_pic:
mov al, 11h
send_init_cmd_to_pic_master:
out 0x20, al
send_init_cmd_to_pic_slave:
out 0xa0, al
; ... ;
make_irq_starts_from_intr_32_in_pic_master:
mov al, 32d
out 0x21, al
make_irq_starts_from_intr_40_in_pic_slave:
mov al, 40d
out 0xa1, al
; ... ;
tell_pic_master_where_pic_slave_is_connected:
mov al, 04h
out 0x21, al
tell_pic_slave_where_pic_master_is_connected:
mov al, 02h
out 0xa1, al
; ... ;
mov al, 01h
tell_pic_master_the_arch_is_x86:
out 0x21, al
tell_pic_slave_the_arch_is_x86:
out 0xa1, al
; ... ;
mov al, 0h
make_pic_master_enables_all_irqs:
out 0x21, al
make_pic_slave_enables_all_irqs:
out 0xa1, al
; ... ;
ret
load_idt:
lidt [idtr - start]
ret
load_task_register:
mov ax, 40d
ltr ax
ret
bits 32
load_page_directory:
mov eax, [page_directory]
mov cr3, eax
ret
enable_paging:
mov eax, cr0
or eax, 80000000h
mov cr0, eax
ret
start_kernel:
mov eax, 10h
mov ds, eax
mov ss, eax
mov eax, 0h
mov es, eax
mov fs, eax
mov gs, eax
sti
call kernel_main
%include "gdt.asm"
%include "idt.asm"
tss:
dd 0
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/Makefile
================================================
ASM = nasm
CC = gcc
BOOTSTRAP_FILE = bootstrap.asm
SIMPLE_KERNEL = simple_kernel.asm
INIT_KERNEL_FILES = starter.asm
KERNEL_FILES = main.c
KERNEL_FLAGS = -Wall -m32 -c -ffreestanding -fno-asynchronous-unwind-tables -fno-pie
KERNEL_OBJECT = -o kernel.elf
build: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
$(CC) $(KERNEL_FLAGS) screen.c -o screen.elf
$(CC) $(KERNEL_FLAGS) process.c -o process.elf
$(CC) $(KERNEL_FLAGS) scheduler.c -o scheduler.elf
$(CC) $(KERNEL_FLAGS) heap.c -o heap.elf
$(CC) $(KERNEL_FLAGS) paging.c -o paging.elf
$(CC) $(KERNEL_FLAGS) ata.c -o ata.elf
$(CC) $(KERNEL_FLAGS) str.c -o str.elf
$(CC) $(KERNEL_FLAGS) filesystem.c -o filesystem.elf
ld -melf_i386 -Tlinker.ld starter.o kernel.elf screen.elf process.elf scheduler.elf heap.elf paging.elf ata.elf str.elf filesystem.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=20
dd seek=21 conv=sync if=/dev/zero of=kernel.img bs=512 count=2046
bochs -f bochs
#qemu-system-x86_64 -machine pc kernel.img
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/ata.c
================================================
#include "ata.h"
void wait_drive_until_ready()
{
int status = 0;
do
{
status = dev_read( BASE_PORT + 7 );
} while ( ( status ^ 0x80 ) == 128 );
}
void *read_disk_chs( int sector )
{
// Part 1
dev_write( BASE_PORT + 6, 0x0a0 );
dev_write( BASE_PORT + 2, 1 );
dev_write( BASE_PORT + 3, sector );
dev_write( BASE_PORT + 4, 0 );
dev_write( BASE_PORT + 5, 0 );
dev_write( BASE_PORT + 7, 0x20 );
// ... //
// Part 2
wait_drive_until_ready();
// ... //
// Part 3
short *buffer = kalloc( SECTOR_SIZE );
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
buffer[ currByte ] = dev_read( BASE_PORT );
return buffer;
}
void *read_disk( int address )
{
dev_write( BASE_PORT + 6, ( 0x0e0 | ( ( address & 0x0F000000 ) >> 24 ) ) );
dev_write( BASE_PORT + 2, 1 );
dev_write( BASE_PORT + 3, address & 0x000000FF );
dev_write( BASE_PORT + 4, ( address & 0x0000FF00 ) >> 8 );
dev_write( BASE_PORT + 5, ( address & 0x00FF0000 ) >> 16 );
dev_write( BASE_PORT + 7, 0x20 );
// ... //
wait_drive_until_ready();
// ... //
short *buffer = kalloc( SECTOR_SIZE );
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
buffer[ currByte ] = dev_read( BASE_PORT );
return buffer;
}
void write_disk_chs( int sector, short *buffer )
{
dev_write( BASE_PORT + 6, 0x0a0 );
dev_write( BASE_PORT + 2, 1 );
dev_write( BASE_PORT + 3, sector );
dev_write( BASE_PORT + 4, 0 );
dev_write( BASE_PORT + 5, 0 );
dev_write( BASE_PORT + 7, 0x30 );
wait_drive_until_ready();
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
dev_write_word( BASE_PORT, buffer[ currByte ] );
wait_drive_until_ready();
}
void write_disk( int address, short *buffer )
{
dev_write( BASE_PORT + 6, ( 0x0e0 | ( ( address & 0x0F000000 ) >> 24 ) ) );
dev_write( BASE_PORT + 2, 1 );
dev_write( BASE_PORT + 3, address & 0x000000FF );
dev_write( BASE_PORT + 4, ( address & 0x0000FF00 ) >> 8 );
dev_write( BASE_PORT + 5, ( address & 0x00FF0000 ) >> 16 );
dev_write( BASE_PORT + 7, 0x30 );
wait_drive_until_ready();
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
dev_write_word( BASE_PORT, buffer[ currByte ] );
wait_drive_until_ready();
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/ata.h
================================================
#define BASE_PORT 0x1F0
#define SECTOR_SIZE 512
void wait_drive_until_ready();
void *read_disk( int );
void write_disk( int, short * );
void *read_disk_chs( int );
void write_disk_chs( int, short * );
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/bochs
================================================
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1, iodebug=1
config_interface: textconfig
display_library: x, options="gui_debug"
memory: host=32, guest=32
romimage: file="/usr/share/bochs/BIOS-bochs-latest"
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: disk
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, mode=flat, translation=auto, path="kernel.img", cylinders=2, heads=16, spt=63, biosdetect=auto, model="Generic 1234"
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: family=6, model=0x03, stepping=3, mmx=1, apic=xapic, sse=sse2, sse4a=0, sep=1, aes=0, xsave=0, xsaveopt=0, movbe=0, adx=0, smep=0, avx=0, avx_f16c=0, avx_fma=0, bmi=0, xop=0, tbm=0, fma4=0, vmx=1, x86_64=1, 1g_pages=0, pcid=0, fsgsbase=0, mwait=1
cpuid: vendor_string="GenuineIntel"
cpuid: brand_string=" Intel(R) Pentium(R) 4 CPU "
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/bootstrap.asm
================================================
start:
mov ax, 07C0h
mov ds, ax
mov si, title_string
call print_string
mov si, message_string
call print_string
call load_kernel_from_disk
jmp 0900h:0000
load_kernel_from_disk:
mov ax, [curr_sector_to_load]
sub ax, 2
mov bx, 512d
mul bx
mov bx, ax
mov ax, 0900h
mov es, ax
mov ah, 02h
mov al, 1h
mov ch, 0h
mov cl, [curr_sector_to_load]
mov dh, 0h
mov dl, 80h
int 13h
jc kernel_load_error
sub byte [number_of_sectors_to_load], 1
add byte [curr_sector_to_load], 1
cmp byte [number_of_sectors_to_load], 0
jne load_kernel_from_disk
ret
kernel_load_error:
mov si, load_error_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; Reading current cursor position
mov ah, 03h
mov bh, 0
int 10h
; Move the cursor to the beginning
mov ah, 02h
mov dl, 0
int 10h
ret
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
number_of_sectors_to_load db 15d
curr_sector_to_load db 2d
times 510-($-$$) db 0
dw 0xAA55
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/filesystem.c
================================================
#include "filesystem.h"
void filesystem_init()
{
base_block = read_disk( BASE_BLOCK_ADDRESS );
}
void create_file( char *filename, char *buffer )
{
int metadata_lba = ( base_block->head == 0 ) ? BASE_BLOCK_ADDRESS + 1 : base_block->tail + 2;
int file_lba = metadata_lba + 1;
metadata_t *metadata = kalloc( sizeof( metadata_t ) );
metadata->next_file_address = 0;
int currIdx;
for ( currIdx = 0; *filename != '\0' && currIdx < FILENAME_LENGTH - 1; currIdx++, filename++ )
metadata->filename[ currIdx ] = *filename;
metadata->filename[ currIdx ] = '\0';
write_disk( metadata_lba, metadata );
write_disk( file_lba, buffer );
if ( base_block->head == 0 )
{
update_base_block( metadata_lba, metadata_lba );
}
else
{
metadata_t *tail_metadata = load_metadata( base_block->tail );
tail_metadata->next_file_address = metadata_lba;
write_disk( base_block->tail, tail_metadata );
update_base_block( base_block->head, metadata_lba );
}
}
char **list_files()
{
// Part 1
if ( base_block->head == 0 )
return -1;
// Part 2
char **list;
list = kalloc( get_files_number() * sizeof( char * ) );
// Part 3
metadata_t *curr_file = load_metadata( base_block->head );
int idx = 0;
while ( 1 )
{
list[ idx ] = curr_file->filename;
if ( curr_file->next_file_address == 0 )
break;
curr_file = load_metadata( curr_file->next_file_address );
idx++;
}
return list;
}
char *read_file( char *filename )
{
int address = get_address_by_filename( filename );
if ( address == 0 )
return 0;
char *buffer = read_disk( address + 1 );
return buffer;
}
void delete_file( char *filename )
{
// Part 1
int curr_file_address = get_address_by_filename( filename );
if ( curr_file_address == 0 )
return;
metadata_t *curr_file_metadata = read_disk( curr_file_address );
// Part 2
if ( get_files_number() == 1 )
{
update_base_block( 0, 0 );
return;
}
// Part 3
if ( curr_file_address == base_block->head )
{
update_base_block( curr_file_metadata->next_file_address, base_block->tail );
}
// Part 4
else
{
int prev_file_address = get_prev_file_address( curr_file_address );
metadata_t *prev_file = load_metadata( prev_file_address );
prev_file->next_file_address = curr_file_metadata->next_file_address;
write_disk( prev_file_address, prev_file );
if ( curr_file_address == base_block->tail )
update_base_block( base_block->head, prev_file_address );
}
}
// ... //
void update_base_block( int new_head, int new_tail )
{
base_block->head = new_head;
base_block->tail = new_tail;
write_disk( BASE_BLOCK_ADDRESS, base_block );
}
metadata_t *load_metadata( int address )
{
metadata_t *metadata = read_disk( address );
return metadata;
}
int get_address_by_filename( char *filename )
{
metadata_t *curr_file = load_metadata( base_block->head );
int curr_file_address = base_block->head;
int idx = 0;
while ( 1 )
{
if ( strcmp( curr_file->filename, filename ) == 1 )
return curr_file_address;
if ( curr_file->next_file_address == 0 )
break;
curr_file_address = curr_file->next_file_address;
curr_file = load_metadata( curr_file->next_file_address );
}
return 0;
}
int get_prev_file_address( int address )
{
metadata_t *prev_file = load_metadata( base_block->head );
int prev_file_address = base_block->head;
while ( 1 )
{
if ( prev_file->next_file_address == address )
return prev_file_address;
prev_file_address = prev_file->next_file_address;
prev_file = load_metadata( prev_file->next_file_address );
}
return -1;
}
int get_files_number()
{
if ( base_block->head == 0 )
return 0;
int files_number = 0;
// ... //
metadata_t *curr_file = load_metadata( base_block->head );
while ( 1 )
{
files_number++;
if ( curr_file->next_file_address == 0 )
break;
curr_file = load_metadata( curr_file->next_file_address );
}
return files_number;
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/filesystem.h
================================================
#define BASE_BLOCK_ADDRESS 100
#define FILENAME_LENGTH 256
typedef struct
{
int head, tail;
} base_block_t;
typedef struct
{
char filename[ FILENAME_LENGTH ];
int next_file_address;
} metadata_t;
base_block_t *base_block;
void filesystem_init();
void create_file( char *, char * );
char **list_files();
char *read_file( char * );
// Auxiliary Functions
metadata_t *load_metadata( int );
int get_address_by_filename( char * );
int get_prev_file_address( int );
int get_files_number();
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/gdt.asm
================================================
gdt:
null_descriptor : dw 0, 0, 0, 0
kernel_code_descriptor : dw 0xffff, 0x0000, 0x9a00, 0x00cf
kernel_data_descriptor : dw 0xffff, 0x0000, 0x9200, 0x00cf
userspace_code_descriptor : dw 0xffff, 0x0000, 0xfa00, 0x00cf
userspace_data_descriptor : dw 0xffff, 0x0000, 0xf200, 0x00cf
tss_descriptor : dw tss + 3, tss, 0x8900, 0x0000
gdtr:
gdt_size_in_bytes : dw ( 6 * 8 )
gdt_base_address : dd gdt
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/heap.c
================================================
#include "heap.h"
void heap_init()
{
heap_base = 0x100000;
}
int kalloc( int bytes )
{
unsigned int new_object_address = heap_base;
heap_base += bytes;
return new_object_address;
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/heap.h
================================================
unsigned int heap_base;
void heap_init();
int kalloc( int );
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/idt.asm
================================================
isr_0:
cli
push 0
jmp isr_basic
isr_1:
cli
push 1
jmp isr_basic
isr_2:
cli
push 2
jmp isr_basic
isr_3:
cli
push 3
jmp isr_basic
isr_4:
cli
push 4
jmp isr_basic
isr_5:
cli
push 5
jmp isr_basic
isr_6:
cli
push 6
jmp isr_basic
isr_7:
cli
push 7
jmp isr_basic
isr_8:
cli
push 8
jmp isr_basic
isr_9:
cli
push 9
jmp isr_basic
isr_10:
cli
push 10
jmp isr_basic
isr_11:
cli
push 11
jmp isr_basic
isr_12:
cli
push 12
jmp isr_basic
isr_13:
cli
push 13
jmp isr_basic
isr_14:
cli
push 14
jmp isr_basic
isr_15:
cli
push 15
jmp isr_basic
isr_16:
cli
push 16
jmp isr_basic
isr_17:
cli
push 17
jmp isr_basic
isr_18:
cli
push 18
jmp isr_basic
isr_19:
cli
push 19
jmp isr_basic
isr_20:
cli
push 20
jmp isr_basic
isr_21:
cli
push 21
jmp isr_basic
isr_22:
cli
push 22
jmp isr_basic
isr_23:
cli
push 23
jmp isr_basic
isr_24:
cli
push 24
jmp isr_basic
isr_25:
cli
push 25
jmp isr_basic
isr_26:
cli
push 26
jmp isr_basic
isr_27:
cli
push 27
jmp isr_basic
isr_28:
cli
push 28
jmp isr_basic
isr_29:
cli
push 29
jmp isr_basic
isr_30:
cli
push 30
jmp isr_basic
isr_31:
cli
push 31
jmp isr_basic
isr_32:
; Part 1
cli ; Step 1
pusha ; Step 2
; Step 3
mov eax, [esp + 32]
push eax
call scheduler ; Step 4
; ... ;
; Part 2
; Step 5
mov al, 0x20
out 0x20, al
; Step 6
add esp, 40d
push run_next_process
iret ; Step 7
isr_33:
cli
push 33
jmp irq_basic
isr_34:
cli
push 34
jmp irq_basic
isr_35:
cli
push 35
jmp irq_basic
isr_36:
cli
push 36
jmp irq_basic
isr_37:
cli
push 37
jmp irq_basic
isr_38:
cli
push 38
jmp irq_basic
isr_39:
cli
push 39
jmp irq_basic
isr_40:
cli
push 40
jmp irq_basic
isr_41:
cli
push 41
jmp irq_basic
isr_42:
cli
push 42
jmp irq_basic
isr_43:
cli
push 43
jmp irq_basic
isr_44:
cli
push 44
jmp irq_basic
isr_45:
cli
push 45
jmp irq_basic
isr_46:
cli
push 46
jmp irq_basic
isr_47:
cli
push 47
jmp irq_basic
isr_48:
cli
push 48
jmp irq_basic
isr_basic:
call interrupt_handler
pop eax
sti
iret
irq_basic:
call interrupt_handler
mov al, 0x20
out 0x20, al
cmp byte [esp], 40d
jnge irq_basic_end
mov al, 0xa0
out 0x20, al
irq_basic_end:
pop eax
sti
iret
idt:
dw isr_0, 8, 0x8e00, 0x0000
dw isr_1, 8, 0x8e00, 0x0000
dw isr_2, 8, 0x8e00, 0x0000
dw isr_3, 8, 0x8e00, 0x0000
dw isr_4, 8, 0x8e00, 0x0000
dw isr_5, 8, 0x8e00, 0x0000
dw isr_6, 8, 0x8e00, 0x0000
dw isr_7, 8, 0x8e00, 0x0000
dw isr_8, 8, 0x8e00, 0x0000
dw isr_9, 8, 0x8e00, 0x0000
dw isr_10, 8, 0x8e00, 0x0000
dw isr_11, 8, 0x8e00, 0x0000
dw isr_12, 8, 0x8e00, 0x0000
dw isr_13, 8, 0x8e00, 0x0000
dw isr_14, 8, 0x8e00, 0x0000
dw isr_15, 8, 0x8e00, 0x0000
dw isr_16, 8, 0x8e00, 0x0000
dw isr_17, 8, 0x8e00, 0x0000
dw isr_18, 8, 0x8e00, 0x0000
dw isr_19, 8, 0x8e00, 0x0000
dw isr_20, 8, 0x8e00, 0x0000
dw isr_21, 8, 0x8e00, 0x0000
dw isr_22, 8, 0x8e00, 0x0000
dw isr_23, 8, 0x8e00, 0x0000
dw isr_24, 8, 0x8e00, 0x0000
dw isr_25, 8, 0x8e00, 0x0000
dw isr_26, 8, 0x8e00, 0x0000
dw isr_27, 8, 0x8e00, 0x0000
dw isr_28, 8, 0x8e00, 0x0000
dw isr_29, 8, 0x8e00, 0x0000
dw isr_30, 8, 0x8e00, 0x0000
dw isr_31, 8, 0x8e00, 0x0000
dw isr_32, 8, 0x8e00, 0x0000
dw isr_33, 8, 0x8e00, 0x0000
dw isr_34, 8, 0x8e00, 0x0000
dw isr_35, 8, 0x8e00, 0x0000
dw isr_36, 8, 0x8e00, 0x0000
dw isr_37, 8, 0x8e00, 0x0000
dw isr_38, 8, 0x8e00, 0x0000
dw isr_39, 8, 0x8e00, 0x0000
dw isr_40, 8, 0x8e00, 0x0000
dw isr_41, 8, 0x8e00, 0x0000
dw isr_42, 8, 0x8e00, 0x0000
dw isr_43, 8, 0x8e00, 0x0000
dw isr_44, 8, 0x8e00, 0x0000
dw isr_45, 8, 0x8e00, 0x0000
dw isr_46, 8, 0x8e00, 0x0000
dw isr_47, 8, 0x8e00, 0x0000
dw isr_48, 8, 0x8e00, 0x0000
idtr:
idt_size_in_bytes : dw idtr - idt
idt_base_address : dd idt
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/linker.ld
================================================
/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */
SECTIONS
{
.text 0x09000 :
{
code = .; _code = .; __code = .;
*(.text)
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
}
end = .; _end = .; __end = .;
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/main.c
================================================
#include "screen.h"
#include "scheduler.h"
#include "heap.h"
void processA();
void processB();
void processC();
void processD();
void print_fs();
void kernel_main()
{
heap_init();
paging_init();
screen_init();
process_init();
scheduler_init();
filesystem_init();
print( "Welcome to 539kernel!" );
println();
print( "We are now in Protected-mode" );
println();
printi( 539 );
println();
process_create( &processA );
process_create( &processB );
process_create( &processC );
process_create( &processD );
// ... //
char *data = kalloc( 512 );
strcpy( data, "The content of the first file on 539filesystem" );
create_file( "first_file", data );
// ... //
char *data2 = kalloc( 512 );
strcpy( data2, "SECOND FILE in 539filesystem" );
create_file( "second_file", data2 );
// ... //
char *data3 = kalloc( 512 );
strcpy( data3, "THIRD FILE in 539filesystem" );
create_file( "third_file", data3 );
// ... //
print( read_file( "first_file" ) ); println();
print( read_file( "second_file" ) ); println();
print( read_file( "third_file" ) ); println();
// ... //
print_fs();
delete_file( "first_file" );
print_fs();
// ... //
while( 1 );
}
void print_fs()
{
char **files = list_files();
for ( int currIdx = 0; currIdx < get_files_number(); currIdx++ )
{
print( "File: " );
print( files[ currIdx ] );
println();
}
print( "==" );
println();
}
void interrupt_handler( int interrupt_number )
{
//println();
//print( "Interrupt Received " );
//printi( interrupt_number );
}
void processA()
{
print( "Process A," );
while ( 1 )
asm( "mov $5390, %eax" );
}
void processB()
{
print( "Process B," );
while ( 1 )
asm( "mov $5391, %eax" );
}
void processC()
{
print( "Process C," );
while ( 1 )
asm( "mov $5392, %eax" );
}
void processD()
{
print( "Process D," );
while ( 1 )
asm( "mov $5393, %eax" );
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/paging.c
================================================
#include "paging.h"
int create_page_entry( int base_address, char present, char writable, char privilege_level, char cache_enabled, char write_through_cache, char accessed, char page_size, char dirty )
{
int entry = 0;
entry |= present;
entry |= writable << 1;
entry |= privilege_level << 2;
entry |= write_through_cache << 3;
entry |= cache_enabled << 4;
entry |= accessed << 5;
entry |= dirty << 6;
entry |= page_size << 7;
return base_address | entry;
}
void paging_init()
{
// PART 1:
unsigned int curr_page_frame = 0;
page_directory = kalloc( 4 * 1024 );
for ( int currPDE = 0; currPDE < PDE_NUM; currPDE++ )
{
unsigned int *pagetable = kalloc( 4 * PTE_NUM );
for ( int currPTE = 0; currPTE < PTE_NUM; currPTE++, curr_page_frame++ )
pagetable[ currPTE ] = create_page_entry( curr_page_frame * 4096, 1, 0, 0, 1, 1, 0, 0, 0 );
page_directory[ currPDE ] = create_page_entry( pagetable, 1, 0, 0, 1, 1, 0, 0, 0 );
}
// ... //
// PART 2
load_page_directory();
enable_paging();
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/paging.h
================================================
#define PDE_NUM 3
#define PTE_NUM 1024
extern void load_page_directory();
extern void enable_paging();
unsigned int *page_directory;
void paging_init();
int create_page_entry( int, char, char, char, char, char, char, char, char );
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/process.c
================================================
#include "process.h"
void process_init()
{
processes_count = 0;
curr_pid = 0;
}
process_t *process_create( int *base_address )
{
process_t *process = kalloc( sizeof( process_t ) );
process->pid = curr_pid++;
process->context.eax = 0;
process->context.ecx = 0;
process->context.edx = 0;
process->context.ebx = 0;
process->context.esp = 0;
process->context.ebp = 0;
process->context.esi = 0;
process->context.edi = 0;
process->context.eip = base_address;
process->state = READY;
process->base_address = base_address;
processes[ process->pid ] = process;
processes_count++;
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/process.h
================================================
typedef enum process_state { READY, RUNNING } process_state_t;
typedef struct process_context
{
int eax, ecx, edx, ebx, esp, ebp, esi, edi, eip;
} process_context_t;
typedef struct process
{
int pid;
process_context_t context;
process_state_t state;
int *base_address;
} process_t;
process_t *processes[ 15 ];
int processes_count, curr_pid;
void process_init();
process_t *process_create( int * );
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/scheduler.c
================================================
#include "scheduler.h"
void scheduler_init()
{
next_sch_pid = 0;
curr_sch_pid = 0;
}
process_t *get_next_process()
{
process_t *next_process = processes[ next_sch_pid ];
curr_sch_pid = next_sch_pid;
next_sch_pid++;
next_sch_pid = next_sch_pid % processes_count;
return next_process;
}
void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax )
{
process_t *curr_process;
print( " EAX = " ); // For Testing Purpose
printi( eax ); // For Testing Purpose
// ... //
// PART 1
curr_process = processes[ curr_sch_pid ];
next_process = get_next_process();
// ... //
// PART 2
if ( curr_process->state == RUNNING )
{
curr_process->context.eax = eax;
curr_process->context.ecx = ecx;
curr_process->context.edx = edx;
curr_process->context.ebx = ebx;
curr_process->context.esp = esp;
curr_process->context.ebp = ebp;
curr_process->context.esi = esi;
curr_process->context.edi = edi;
curr_process->context.eip = eip;
}
curr_process->state = READY;
// ... //
// PART 3
asm( " mov %0, %%eax; \
mov %0, %%ecx; \
mov %0, %%edx; \
mov %0, %%ebx; \
mov %0, %%esi; \
mov %0, %%edi;"
: : "r" ( next_process->context.eax ), "r" ( next_process->context.ecx ), "r" ( next_process->context.edx ), "r" ( next_process->context.ebx ),
"r" ( next_process->context.esi ), "r" ( next_process->context.edi ) );
next_process->state = RUNNING;
}
void run_next_process()
{
asm( " sti; \
jmp *%0" : : "r" ( next_process->context.eip ) );
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/scheduler.h
================================================
#include "process.h"
int next_sch_pid, curr_sch_pid;
process_t *next_process;
void scheduler_init();
process_t *get_next_process();
void scheduler( int, int, int, int, int, int, int, int, int );
void run_next_process();
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/screen.c
================================================
#include "screen.h"
void screen_init()
{
video = 0xB8000;
nextTextPos = 0;
currLine = 0;
}
void print( char *str )
{
int currCharLocationInVidMem, currColorLocationInVidMem;
while ( *str != '\0' )
{
currCharLocationInVidMem = nextTextPos * 2;
currColorLocationInVidMem = currCharLocationInVidMem + 1;
video[ currCharLocationInVidMem ] = *str;
video[ currColorLocationInVidMem ] = 15;
nextTextPos++;
str++;
}
}
void println()
{
nextTextPos = ++currLine * 80;
}
void printi( int number )
{
char* digitToStr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if ( number >= 0 && number <= 9 )
{
print( digitToStr[ number ] );
return;
}
else
{
int remaining = number % 10;
number = number / 10;
printi( number );
printi( remaining );
}
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/screen.h
================================================
volatile unsigned char *video;
int nextTextPos;
int currLine;
void screen_init();
void print( char * );
void println();
void printi( int );
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/starter.asm
================================================
bits 16
extern kernel_main
extern interrupt_handler
extern scheduler
extern run_next_process
extern page_directory
global load_page_directory
global enable_paging
global dev_write
global dev_write_word
global dev_read
start:
mov ax, cs
mov ds, ax
call load_gdt
call init_video_mode
call enter_protected_mode
call setup_interrupts
call load_task_register
call 08h:start_kernel
load_gdt:
cli
lgdt [gdtr - start]
ret
enter_protected_mode:
mov eax, cr0
or eax, 1
mov cr0, eax
ret
init_video_mode:
mov ah, 0h
mov al, 03h
int 10h
mov ah, 01h
mov cx, 2000h
int 10h
ret
setup_interrupts:
call remap_pic
call load_idt
ret
remap_pic:
mov al, 11h
send_init_cmd_to_pic_master:
out 0x20, al
send_init_cmd_to_pic_slave:
out 0xa0, al
; ... ;
make_irq_starts_from_intr_32_in_pic_master:
mov al, 32d
out 0x21, al
make_irq_starts_from_intr_40_in_pic_slave:
mov al, 40d
out 0xa1, al
; ... ;
tell_pic_master_where_pic_slave_is_connected:
mov al, 04h
out 0x21, al
tell_pic_slave_where_pic_master_is_connected:
mov al, 02h
out 0xa1, al
; ... ;
mov al, 01h
tell_pic_master_the_arch_is_x86:
out 0x21, al
tell_pic_slave_the_arch_is_x86:
out 0xa1, al
; ... ;
mov al, 0h
make_pic_master_enables_all_irqs:
out 0x21, al
make_pic_slave_enables_all_irqs:
out 0xa1, al
; ... ;
ret
load_idt:
lidt [idtr - start]
ret
load_task_register:
mov ax, 40d
ltr ax
ret
bits 32
load_page_directory:
mov eax, [page_directory]
mov cr3, eax
ret
enable_paging:
mov eax, cr0
or eax, 80000000h
mov cr0, eax
ret
dev_write:
; Part 1
push edx
push eax
; Part 2
xor edx, edx
xor eax, eax
; Part 3
mov dx, [esp + 12]
mov al, [esp + 16]
; Part 4
out dx, al
; Part 5
pop eax
pop edx
ret
dev_write_word:
push edx
push eax
xor edx, edx
xor eax, eax
mov dx, [esp + 12]
mov ax, [esp + 16]
out dx, ax
pop eax
pop edx
ret
dev_read:
push edx
xor edx, edx
xor eax, eax
mov dx, [esp + 8]
in ax, dx
pop edx
ret
start_kernel:
mov eax, 10h
mov ds, eax
mov ss, eax
mov eax, 0h
mov es, eax
mov fs, eax
mov gs, eax
;sti
call kernel_main
%include "gdt.asm"
%include "idt.asm"
tss:
dd 0
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/str.c
================================================
#include "str.h"
void strcpy( char *dest, char *src )
{
int idx = 0;
while ( *src != '\0' )
{
dest[ idx ] = *src;
src++;
idx++;
}
}
int strcmp( char *str1, char *str2 )
{
while ( *str1 != '\0' )
{
if ( *str1 != *str2 )
return 0;
str1++;
str2++;
}
if ( *str2 != '\0' )
return 0;
return 1;
}
================================================
FILE: evolution_by_versions/06_539kernel_version_ne/str.h
================================================
void strcpy( char *, char * );
int strcmp( char *, char * );
================================================
FILE: src/.gitignore
================================================
# Created by https://www.gitignore.io/api/c
# Edit at https://www.gitignore.io/?templates=c
### C ###
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
*.bin
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# End of https://www.gitignore.io/api/c
*.img
================================================
FILE: src/Makefile
================================================
ASM = nasm
CC = gcc
BOOTSTRAP_FILE = bootstrap.asm
SIMPLE_KERNEL = simple_kernel.asm
INIT_KERNEL_FILES = starter.asm
KERNEL_FILES = main.c
# -m32 means generate 32-bit code. See "Machine-Dependent Options" section in gcc man page for details. Under "x86 Options" section "-m flag".
#
# -Wall:
# "This enables all the warnings about constructions that some
# users consider questionable, and that are easy to avoid (or
# modify to prevent the warning), even in conjunction with
# macros. This also enables some language-specific warnings
# described in C++ Dialect Options and Objective-C and
# Objective-C++ Dialect Options."
# ~ GCC man page
#
# -c:
# "If any of these options is used [-c, -S, -E], then the linker is not run, and object file names should not be used as arguments."
# ~ GCC man page
#
# -ffreestanding:
# "Assert that compilation targets a freestanding environment.
# This implies -fno-builtin. A freestanding environment is one
# in which the standard library may not exist, and program
# startup may not necessarily be at "main". The most obvious
# example is an OS kernel. This is equivalent to -fno-hosted."
# ~ GCC man page
#
# -no-pie:
# "Don't produce a dynamically linked position independent executable."
# ~ GCC man page
#
# -g:
# "To tell GCC to emit extra information for use by a debugger, in almost all cases you need only to add -g to your other options."
# ~ GCC man page
#
# -std=
# "Determine the language standard. This option is currently only supported when compiling C or C++."
# gnu99: "GNU dialect of ISO C99. The name gnu9x is deprecated."
# gnu18: "GNU dialect of ISO C17. This is the default for C code."
# ~ GCC man page
#-std=gnu99 # -c -Wall -no-pie -g -std=gnu99
KERNEL_FLAGS = -Wall -m32 -c -ffreestanding -fno-asynchronous-unwind-tables -fno-pie -fcommon -fno-stack-protector
# -O1 -fno-pie
KERNEL_OBJECT = -o kernel.elf
build:
echo Please Choose Type
kernel: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
$(CC) $(KERNEL_FLAGS) screen.c -o screen.elf
$(CC) $(KERNEL_FLAGS) process.c -o process.elf
$(CC) $(KERNEL_FLAGS) scheduler.c -o scheduler.elf
$(CC) $(KERNEL_FLAGS) heap.c -o heap.elf
$(CC) $(KERNEL_FLAGS) paging.c -o paging.elf
$(CC) $(KERNEL_FLAGS) ata.c -o ata.elf
$(CC) $(KERNEL_FLAGS) str.c -o str.elf
$(CC) $(KERNEL_FLAGS) filesystem.c -o filesystem.elf
ld -melf_i386 -Tlinker.ld starter.o kernel.elf screen.elf process.elf scheduler.elf heap.elf paging.elf ata.elf str.elf filesystem.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=20
dd seek=21 conv=sync if=/dev/zero of=kernel.img bs=512 count=2046
bochs -f bochs
#qemu-system-x86_64 -s kernel.img
debug: $(BOOTSTRAP_FILE) $(KERNEL_FILE)
$(ASM) -f bin $(BOOTSTRAP_FILE) -o bootstrap.o
$(ASM) -f elf32 $(INIT_KERNEL_FILES) -o starter.o
$(CC) $(KERNEL_FLAGS) $(KERNEL_FILES) $(KERNEL_OBJECT)
$(CC) $(KERNEL_FLAGS) screen.c -o screen.elf
$(CC) $(KERNEL_FLAGS) process.c -o process.elf
$(CC) $(KERNEL_FLAGS) scheduler.c -o scheduler.elf
$(CC) $(KERNEL_FLAGS) heap.c -o heap.elf
$(CC) $(KERNEL_FLAGS) paging.c -o paging.elf
$(CC) $(KERNEL_FLAGS) ata.c -o ata.elf
$(CC) $(KERNEL_FLAGS) str.c -o str.elf
$(CC) $(KERNEL_FLAGS) filesystem.c -o filesystem.elf
ld -melf_i386 -Tlinker.ld starter.o kernel.elf screen.elf process.elf scheduler.elf heap.elf paging.elf ata.elf str.elf filesystem.elf -o 539kernel.elf
objcopy -O binary 539kernel.elf 539kernel.bin
dd if=bootstrap.o of=kernel.img
dd seek=1 conv=sync if=539kernel.bin of=kernel.img bs=512 count=20
dd seek=21 conv=sync if=/dev/zero of=kernel.img bs=512 count=2045
bochs -f bochs
rerun-debug:
bochs -f bochs
rerun-kernel:
qemu-system-x86_64 -s kernel.img
clean:
rm -f *.o
rm -f *.elf
rm -f *.img
rm -f *.bin
================================================
FILE: src/README
================================================
[MQH] 25 Nov 2019
Here is the final code of 539kernel. Any incremental steps, examples and excercises can be found in ../examples.
================================================
FILE: src/ata.c
================================================
#include "ata.h"
void wait_drive_until_ready()
{
int status = 0;
do
{
status = dev_read( BASE_PORT + 7 );
} while ( ( status ^ 0x80 ) == 128 );
}
// LBA
void *read_disk( int address )
{
dev_write( BASE_PORT + 6, ( 0x0e0 | ( ( address & 0x0F000000 ) >> 24 ) ) ); // Drive 0. Bits 0-3 = Bits 24-27 of LBA
dev_write( BASE_PORT + 2, 1 ); // Sector count
dev_write( BASE_PORT + 3, address & 0x000000FF ); // LBA's 0-7 bits
dev_write( BASE_PORT + 4, ( address & 0x0000FF00 ) >> 8 ); // LBA's 8-15 bits
dev_write( BASE_PORT + 5, ( address & 0x00FF0000 ) >> 16 ); // LBA's 16-23 bits
dev_write( BASE_PORT + 7, 0x20 ); // Command: Read with Retry
// ... //
wait_drive_until_ready();
// ... //
short *buffer = kalloc( SECTOR_SIZE );
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
buffer[ currByte ] = dev_read( BASE_PORT );
return buffer;
}
// LBA
void write_disk( int address, short *buffer )
{
dev_write( BASE_PORT + 6, ( 0x0e0 | ( ( address & 0x0F000000 ) >> 24 ) ) ); // Drive 0. Bits 0-3 = Bits 24-27 of LBA
dev_write( BASE_PORT + 2, 1 ); // Sector count
dev_write( BASE_PORT + 3, address & 0x000000FF ); // LBA's 0-7 bits
dev_write( BASE_PORT + 4, ( address & 0x0000FF00 ) >> 8 ); // LBA's 8-15 bits
dev_write( BASE_PORT + 5, ( address & 0x00FF0000 ) >> 16 ); // LBA's 16-23 bits
dev_write( BASE_PORT + 7, 0x30 ); // Command: Write with Retry
wait_drive_until_ready();
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
dev_write_word( BASE_PORT, buffer[ currByte ] );
wait_drive_until_ready();
}
void *read_disk_chs( int sector )
{
dev_write( BASE_PORT + 6, 0x0a0 ); // Drive 0 and Head 0
dev_write( BASE_PORT + 2, 1 ); // Sector count
dev_write( BASE_PORT + 3, sector ); // Sector to read
dev_write( BASE_PORT + 4, 0 ); // Cylinder - Low
dev_write( BASE_PORT + 5, 0 ); // Cylinder - High
dev_write( BASE_PORT + 7, 0x20 ); // Command: Read with Retry
// ... //
wait_drive_until_ready();
// ... //
short *buffer = kalloc( SECTOR_SIZE );
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
buffer[ currByte ] = dev_read( BASE_PORT );
return buffer;
}
void write_disk_chs( int sector, short *buffer )
{
dev_write( BASE_PORT + 6, 0x0a0 ); // Drive 0 and Head 0
dev_write( BASE_PORT + 2, 1 ); // Sector count
dev_write( BASE_PORT + 3, sector ); // Sector to read
dev_write( BASE_PORT + 4, 0 ); // Cylinder - Low
dev_write( BASE_PORT + 5, 0 ); // Cylinder - High
dev_write( BASE_PORT + 7, 0x30 ); // Command: Write with Retry
// ... //
wait_drive_until_ready();
// ... //
for ( int currByte = 0; currByte < ( SECTOR_SIZE / 2 ); currByte++ )
dev_write_word( BASE_PORT, buffer[ currByte ] );
// ... //
wait_drive_until_ready();
}
================================================
FILE: src/ata.h
================================================
#define BASE_PORT 0x1F0
#define SECTOR_SIZE 512
void wait_drive_until_ready();
void *read_disk( int );
void write_disk( int, short * );
void *read_disk_chs( int );
void write_disk_chs( int, short * );
================================================
FILE: src/bochs
================================================
# configuration file generated by Bochs
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1, iodebug=1
config_interface: textconfig
display_library: x, options="gui_debug"
memory: host=32, guest=32
romimage: file="/usr/share/bochs/BIOS-bochs-latest"
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: disk
floppy_bootsig_check: disabled=0
# no floppya
# no floppyb
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, mode=flat, translation=auto, path="kernel.img", cylinders=2, heads=16, spt=63, biosdetect=auto, model="Generic 1234"
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata2: enabled=0
ata3: enabled=0
pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
cpu: count=1, ips=4000000, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: family=6, model=0x03, stepping=3, mmx=1, apic=xapic, sse=sse2, sse4a=0, sep=1, aes=0, xsave=0, xsaveopt=0, movbe=0, adx=0, smep=0, avx=0, avx_f16c=0, avx_fma=0, bmi=0, xop=0, tbm=0, fma4=0, vmx=1, x86_64=1, 1g_pages=0, pcid=0, fsgsbase=0, mwait=1
cpuid: vendor_string="GenuineIntel"
cpuid: brand_string=" Intel(R) Pentium(R) 4 CPU "
print_timestamps: enabled=0
debugger_log: -
magic_break: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
# no loader
log: -
logprefix: %t%e%d
panic: action=ask
error: action=report
info: action=report
debug: action=ignore
keyboard: type=mf, serial_delay=250, paste_delay=100000, keymap=
user_shortcut: keys=none
mouse: enabled=0, type=ps2, toggle=ctrl+mbutton
parport1: enabled=1, file=""
parport2: enabled=0
com1: enabled=1, mode=null, dev=""
com2: enabled=0
com3: enabled=0
com4: enabled=0
================================================
FILE: src/bootstrap.asm
================================================
start:
; [MQH] 3 Sep 2019
; When a the boot sector is loaded by BIOS. It will be loaded on the location 07C0h in the memory.
; What we do here is setting the register "ds" to the value "07C0" which is the same of the memory address we are on now.
; Our variable "hello_string" will be loaded as a part of the bootloader, when we use it in the line "mov si, hello_string"
; we're actually loading the memory address of the first character, let's assume that this memory address is (1000). Because
; it is considered as a "data" by the processor. This offset (the memory address of "hello_string") will be added to the data segment
; selector which resides in the register "ds". According to "Protected Mode Software Architecture", the initial value of "ds" is 0000h,
; so, if we keep "ds" as it is, the CPU is going to load the data from the memory 00001000, BUT we are actually on 07C0, so the data
; segment selector should be 07C0h so we can get the correct address of "hello_string" which is 07C01000 and not 00001000.
; For backward compatibility, when the bootloader starts, the execution environment will be in "Real Mode", 16-bit.
mov ax, 07C0h
mov ds, ax
; ... ;
; == Printing == ;
mov si, title_string
call print_string ; "CALL" is used instead of "JMP" because we would like to return to the next instruction after "print_string" finishes.
mov si, message_string
call print_string
; ... ;
; === Loading the Kernel === ;
call load_kernel_from_disk
; If the loading has been performed correctly. Jump to the kernel's code which resides on 0900h:0000 according
; to ES:BX values before calling (int 13h).
;
; There is a difference between "JMP" and "CALL" inctructions. The first one doesn't store returning information
; in the stack while the later does. Because we are not going to return from kernel to the bootloader, we don't
; need to store return information.
jmp 0900h:0000
; ... ;
; ... ;
load_kernel_from_disk:
; [MQH] 26 Nov 2019
; BIOS provides disk services through intrrupt 13h. The value of the register "ah" decides which disk service that we are requesting from BIOS.
; The Disk Service "02h" loads sectors to the memory. The memory location that we would like to load our kernel in should be decided
; before calling "int 13h". There are two parts of this location. The first part (segment selector) resides in the register "ES" while
; the other part (offset) resides in the register "BX".
;
; x86 Segment Registers: CS: for code segment.
; DS, ES, FS, and GS: for 4 data segments.
; SS: for stack segment.
; They are 16-bit registers that hold "segment selectors"
mov ax, [curr_sector_to_load]
sub ax, 2
mov bx, 512d
mul bx
mov bx, ax
mov ax, 0900h
mov es, ax
mov ah, 02h ; Requesting the service of reading disk sectors
mov al, 1h ; Number of sectors to read (How many sectors to read?)
mov ch, 0h ; Track number
mov cl, [curr_sector_to_load] ; Sector number
mov dh, 0h ; Head number
mov dl, 80h ; Drive to read from. (0 = Floppy. 80h = Drive #0. 81h = Drive #1)
int 13h ; BIOS Disk Services
; The instruction "jc" jumps to a memory location when CF = 1 (jc = jump if carry).
; CF (or carry flag) is the first bit of EFLAG register in x86. The BIOS service (13h,02h)
; clear CF (that is, put 0 in CF) when everything is fine. But if there is some error
; it's going to set CF (that is, put 1 in CF). Error code will be in "ah".
;
; If any error happens in loading our kernel. The bootloader is going to jump to the label "kernel_load_error".
jc kernel_load_error
sub byte [number_of_sectors_to_load], 1
add byte [curr_sector_to_load], 1
cmp byte [number_of_sectors_to_load], 0
jne load_kernel_from_disk
ret
; When the bootloader fails to load the kernel. A nice message is printted for the user.
kernel_load_error:
mov si, load_error_string
call print_string
; "$" is a special expression in NASM. It means the starting memory address (or assembly position?) of current instruction, that means
; the following instruction is going to loop forever.
jmp $
; ... ;
; ... ;
; [MQH] 3 Sep 2019
; BIOS provides video services through intrrupt 10h. The value of the register "ah" decides which video service that we are requesting from BIOS.
; Those BIOS services are only available on Real Mode (https://stackoverflow.com/questions/26448480/bios-interrupts-in-protected-mode)
;
; ah = 0Eh means that we wish to print a character in TTY mode.
; For an example of using service "0Eh" to print "Hello" character by character, please refer to "../examples/bootstrap/1/".
print_string:
mov ah, 0Eh
print_char:
; [MQH] 26 Nov 2019
; It's known that a byte = 8 bits. In x86 there are more two units: a "word" = 16 bits and "doubleword" = 32 bits. Some x86 instructions have multiple variants that work
; with a specific aforementioned unit. "lods" is an example of these instructions, there is "lodsb" which works with a byte, "lodsw" which works with a word and "lodsd" which
; works with doubleword.
;
; The instruction "lods" uses the value which is stored in register "si" (when using lodsb or loadsw) or register "esi" (when using lodsw) and assume that this
; value as memory location. Then according to the used unit a (b)yte (8-bits), (w)ord (16-bits) or (d)oubleword (32-bit) will be read from the memory location DS:(E)SI
; and store these bits in al, ax or eax according to the size of read data.
lodsb
cmp al, 0
je printing_finished
int 10h
jmp print_char
printing_finished:
mov al, 10d ; Print new line
int 10h
; [MQH] NEW 25 June 2021
; Move the cursor to the beginning
mov ah, 03h
mov bh, 0
int 10h
mov ah, 02h
mov dl, 0
int 10h
; print_string is a procedure (or function), therefore we should return. It is called by using "CALL" instead of "JMP".
ret
; ... ;
; [MQH] 9 Dec 2019
; "DB" is one of pseudo-instructions which is provided by NASM. A source line in NASM follows the following format
; label: instruction operands ; comment
; The label is optional and even the colon after the label is optional.
; "DB" is used to declare initialized data. The "B" in "DB" means byte.
; the part ", 0" means that the last byte will be 0. In some way resembles
; nul character in C strings.
;
; Put the string in the output of this assembly file. Byte by byte, and the address of
; this string will be in the label, so we can reach the string inside the assembly source code.
title_string db 'The Bootloader of 539kernel.', 0
message_string db 'The kernel is loading...', 0
load_error_string db 'The kernel cannot be loaded', 0
number_of_sectors_to_load db 15d ; 255 sectors = 127.5KB ; [MQH] NEW 4 July 2021
curr_sector_to_load db 2d
; [MQH] 9 Dec 2019
; "TIMES" is an NASM pseudo-instruction which repeats an instruction a number of specific times.
; The first operand of "TIMES" is the number of repetitions.
; As we mentioned before "$" means the starting address (or assembly position?) of current instruction.
; "$$" is another special expression which means the starting address (or assembly position?) of current section.
; So, we know that the size of bootstrap should be 512 byte. Two bytes are represent the magic code in the last line
; so 510 bytes remains for us. Our code starts from position $$ and we reached position $. Therefore, $ - $$ gives
; us the size of our code. So, 510 - ( $ - $$ ) gives us the remaining size of the 512 bytes and fills it with zeros
; by using "DB".
times 510-($-$$) db 0
; Put the magic code of bootloader in the end of assembly file's output. "W" means word.
dw 0xAA55
================================================
FILE: src/filesystem.c
================================================
#include "filesystem.h"
void filesystem_init()
{
base_block = read_disk( BASE_BLOCK_ADDRESS );
}
void update_base_block( int new_head, int new_tail )
{
base_block->head = new_head;
base_block->tail = new_tail;
write_disk( BASE_BLOCK_ADDRESS, base_block );
}
metadata_t *load_metadata( int address )
{
metadata_t *metadata = read_disk( address );
return metadata;
}
int get_files_number()
{
if ( base_block->head == 0 )
return 0;
int files_number = 0;
// ... //
metadata_t *curr_file = load_metadata( base_block->head );
while ( 1 )
{
files_number++;
if ( curr_file->next_file_address == 0 )
break;
curr_file = load_metadata( curr_file->next_file_address );
}
return files_number;
}
void create_file( char *filename, char *buffer )
{
int metadata_lba = ( base_block->head == 0 ) ? BASE_BLOCK_ADDRESS + 1 : base_block->tail + 2;
int file_lba = metadata_lba + 1;
metadata_t *metadata = kalloc( sizeof( metadata_t ) );
metadata->next_file_address = 0;
// ... //
int currIdx;
for ( currIdx = 0; *filename != '\0' && currIdx < FILENAME_LENGTH - 1; currIdx++, filename++ )
metadata->filename[ currIdx ] = *filename;
metadata->filename[ currIdx ] = '\0';
// ... //
write_disk( metadata_lba, metadata );
write_disk( file_lba, buffer );
// ... //
if ( base_block->head == 0 )
{
update_base_block( metadata_lba, metadata_lba );
}
else
{
metadata_t *tail_metadata = load_metadata( base_block->tail );
tail_metadata->next_file_address = metadata_lba;
write_disk( base_block->tail, tail_metadata );
update_base_block( base_block->head, metadata_lba );
}
}
char **list_files()
{
if ( base_block->head == 0 )
return -1;
char **list;
list = kalloc( get_files_number() * sizeof( char * ) );
metadata_t *curr_file = load_metadata( base_block->head );
int idx = 0;
while ( 1 )
{
list[ idx ] = curr_file->filename;
if ( curr_file->next_file_address == 0 )
break;
curr_file = load_metadata( curr_file->next_file_address );
idx++;
}
return list;
}
int get_address_by_filename( char *filename )
{
metadata_t *curr_file = load_metadata( base_block->head );
int curr_file_address = base_block->head;
int idx = 0;
while ( 1 )
{
if ( strcmp( curr_file->filename, filename ) == 1 )
return curr_file_address;
if ( curr_file->next_file_address == 0 )
break;
curr_file_address = curr_file->next_file_address;
curr_file = load_metadata( curr_file->next_file_address );
}
return 0;
}
char *read_file( char *filename )
{
int address = get_address_by_filename( filename );
if ( address == 0 )
return 0;
printi( address );
char *buffer = read_disk( address + 1 );
return buffer;
}
int get_prev_file_address( int address )
{
metadata_t *prev_file = load_metadata( base_block->head );
int prev_file_address = base_block->head;
while ( 1 )
{
if ( prev_file->next_file_address == address )
return prev_file_address;
prev_file_address = prev_file->next_file_address;
prev_file = load_metadata( prev_file->next_file_address );
}
return -1;
}
void delete_file( char *filename )
{
int curr_file_address = get_address_by_filename( filename );
if ( curr_file_address == 0 )
return;
// ... //
if ( get_files_number() == 1 )
{
update_base_block( 0, 0 );
return;
}
metadata_t *curr_file_metadata = read_disk( curr_file_address );
if ( curr_file_address == base_block->head )
{
update_base_block( curr_file_metadata->next_file_address, base_block->tail );
}
else
{
int prev_file_address = get_prev_file_address( curr_file_address );
metadata_t *prev_file = load_metadata( prev_file_address );
prev_file->next_file_address = curr_file_metadata->next_file_address;
write_disk( prev_file_address, prev_file );
if ( curr_file_address == base_block->tail )
update_base_block( base_block->head, prev_file_address );
}
}
================================================
FILE: src/filesystem.h
================================================
#define BASE_BLOCK_ADDRESS 100
#define FILENAME_LENGTH 256
typedef struct
{
int head, tail;
} base_block_t;
typedef struct
{
char filename[ FILENAME_LENGTH ];
int next_file_address;
} metadata_t;
base_block_t *base_block;
void filesystem_init();
void create_file( char *, char * );
char **list_files();
char *read_file( char * );
// Auxiliary Functions
metadata_t *load_metadata( int );
int get_address_by_filename( char * );
int get_prev_file_address( int );
int get_files_number();
================================================
FILE: src/gdt.asm
================================================
; The values of the decriptors from Basekernel (kernelcode.S) (https://github.com/dthain/basekernel)
gdt:
null_descriptor : dw 0, 0, 0, 0
kernel_code_descriptor : dw 0xffff, 0x0000, 0x9a00, 0x00cf
kernel_data_descriptor : dw 0xffff, 0x0000, 0x9200, 0x00cf
userspace_code_descriptor : dw 0xffff, 0x0000, 0xfa00, 0x00cf
userspace_data_descriptor : dw 0xffff, 0x0000, 0xf200, 0x00cf
; DON'T FORGET TO CHANGE THE SIZE OF THE GDT
; TODO: I think the limit isn't correct
tss_descriptor : dw tss + 3, tss, 0x8900, 0x0000
gdtr:
gdt_size_in_bytes : dw ( 6 * 8 ) ;= 28h
gdt_base_address : dd gdt
================================================
FILE: src/heap.c
================================================
#include "heap.h"
void heap_init()
{
heap_base = 0x100000;
}
int kalloc( int bytes )
{
// Note: Not necessarily page-aligned
unsigned int new_object_address = heap_base;
heap_base += bytes;
return new_object_address;
}
================================================
FILE: src/heap.h
================================================
unsigned int heap_base;
void heap_init();
int kalloc( int );
================================================
FILE: src/idt.asm
================================================
isr_0:
cli
push 0
jmp isr_basic
isr_1:
cli
push 1
jmp isr_basic
isr_2:
cli
push 2
jmp isr_basic
isr_3:
cli
push 3
jmp isr_basic
isr_4:
cli
push 4
jmp isr_basic
isr_5:
cli
push 5
jmp isr_basic
isr_6:
cli
push 6
jmp isr_basic
isr_7:
cli
push 7
jmp isr_basic
isr_8:
cli
push 8
jmp isr_basic
isr_9:
cli
push 9
jmp isr_basic
isr_10:
cli
push 10
jmp isr_basic
isr_11:
cli
push 11
jmp isr_basic
isr_12:
cli
push 12
jmp isr_basic
isr_13:
cli
push 13
jmp isr_basic
isr_14:
cli
push 14
jmp isr_basic
isr_15:
cli
push 15
jmp isr_basic
isr_16:
cli
push 16
jmp isr_basic
isr_17:
cli
push 17
jmp isr_basic
isr_18:
cli
push 18
jmp isr_basic
isr_19:
cli
push 19
jmp isr_basic
isr_20:
cli
push 20
jmp isr_basic
isr_21:
cli
push 21
jmp isr_basic
isr_22:
cli
push 22
jmp isr_basic
isr_23:
cli
push 23
jmp isr_basic
isr_24:
cli
push 24
jmp isr_basic
isr_25:
cli
push 25
jmp isr_basic
isr_26:
cli
push 26
jmp isr_basic
isr_27:
cli
push 27
jmp isr_basic
isr_28:
cli
push 28
jmp isr_basic
isr_29:
cli
push 29
jmp isr_basic
isr_30:
cli
push 30
jmp isr_basic
isr_31:
cli
push 31
jmp isr_basic
; System Timer
isr_32:
cli
pusha ; Store the context of current process
mov eax, [esp + 32] ; EIP before interrupt. Could be the EIP of the current process
push eax
call scheduler
mov al, 0x20
out 0x20, al
add esp, 40d ; Remove return address from stack, EIP and all general purpose registers of previous process.
push run_next_process
iret
isr_33:
cli
push 33
jmp irq_basic
isr_34:
cli
push 34
jmp irq_basic
isr_35:
cli
push 35
jmp irq_basic
isr_36:
cli
push 36
jmp irq_basic
isr_37:
cli
push 37
jmp irq_basic
isr_38:
cli
push 38
jmp irq_basic
isr_39:
cli
push 39
jmp irq_basic
isr_40:
cli
push 40
jmp irq_basic
isr_41:
cli
push 41
jmp irq_basic
isr_42:
cli
push 42
jmp irq_basic
isr_43:
cli
push 43
jmp irq_basic
isr_44:
cli
push 44
jmp irq_basic
isr_45:
cli
push 45
jmp irq_basic
isr_46:
cli
push 46
jmp irq_basic
isr_47:
cli
push 47
jmp irq_basic
isr_48:
cli
push 48
jmp irq_basic
isr_basic:
; cli
call interrupt_handler
pop eax
sti
iret
irq_basic:
; cli
call interrupt_handler
mov al, 0x20
out 0x20, al
cmp byte [esp], 40d ; Interrupt number
jnge irq_basic_end
mov al, 0xa0
out 0x20, al
irq_basic_end:
pop eax
sti
iret
; The value of the flags from Basekernel (kernelcode.S) (https://github.com/dthain/basekernel)
idt:
dw isr_0, 8, 0x8e00, 0x0000
dw isr_1, 8, 0x8e00, 0x0000
dw isr_2, 8, 0x8e00, 0x0000
dw isr_3, 8, 0x8e00, 0x0000
dw isr_4, 8, 0x8e00, 0x0000
dw isr_5, 8, 0x8e00, 0x0000
dw isr_6, 8, 0x8e00, 0x0000
dw isr_7, 8, 0x8e00, 0x0000
dw isr_8, 8, 0x8e00, 0x0000
dw isr_9, 8, 0x8e00, 0x0000
dw isr_10, 8, 0x8e00, 0x0000
dw isr_11, 8, 0x8e00, 0x0000
dw isr_12, 8, 0x8e00, 0x0000
dw isr_13, 8, 0x8e00, 0x0000
dw isr_14, 8, 0x8e00, 0x0000
dw isr_15, 8, 0x8e00, 0x0000
dw isr_16, 8, 0x8e00, 0x0000
dw isr_17, 8, 0x8e00, 0x0000
dw isr_18, 8, 0x8e00, 0x0000
dw isr_19, 8, 0x8e00, 0x0000
dw isr_20, 8, 0x8e00, 0x0000
dw isr_21, 8, 0x8e00, 0x0000
dw isr_22, 8, 0x8e00, 0x0000
dw isr_23, 8, 0x8e00, 0x0000
dw isr_24, 8, 0x8e00, 0x0000
dw isr_25, 8, 0x8e00, 0x0000
dw isr_26, 8, 0x8e00, 0x0000
dw isr_27, 8, 0x8e00, 0x0000
dw isr_28, 8, 0x8e00, 0x0000
dw isr_29, 8, 0x8e00, 0x0000
dw isr_30, 8, 0x8e00, 0x0000
dw isr_31, 8, 0x8e00, 0x0000
dw isr_32, 8, 0x8e00, 0x0000
dw isr_33, 8, 0x8e00, 0x0000
dw isr_34, 8, 0x8e00, 0x0000
dw isr_35, 8, 0x8e00, 0x0000
dw isr_36, 8, 0x8e00, 0x0000
dw isr_37, 8, 0x8e00, 0x0000
dw isr_38, 8, 0x8e00, 0x0000
dw isr_39, 8, 0x8e00, 0x0000
dw isr_40, 8, 0x8e00, 0x0000
dw isr_41, 8, 0x8e00, 0x0000
dw isr_42, 8, 0x8e00, 0x0000
dw isr_43, 8, 0x8e00, 0x0000
dw isr_44, 8, 0x8e00, 0x0000
dw isr_45, 8, 0x8e00, 0x0000
dw isr_46, 8, 0x8e00, 0x0000
dw isr_47, 8, 0x8e00, 0x0000
dw isr_48, 8, 0x8e00, 0x0000
idtr:
idt_size_in_bytes : dw idtr - idt
idt_base_address : dd idt
================================================
FILE: src/linker.ld
================================================
/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */
SECTIONS
{
.text 0x09000 :
{
code = .; _code = .; __code = .;
*(.text)
/*. = ALIGN(4096);*/
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
/*. = ALIGN(4096);*/
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
/*. = ALIGN(4096);*/
}
end = .; _end = .; __end = .;
}
================================================
FILE: src/main.c
================================================
#include "heap.h"
#include "paging.h"
#include "screen.h"
#include "scheduler.h"
#include "ata.h"
#include "filesystem.h"
#include "str.h"
void processA();
void processB();
void processC();
void processD();
void print_fs()
{
char **files = list_files();
for ( int currIdx = 0; currIdx < get_files_number(); currIdx++ )
{
print( "File: " );
print( files[ currIdx ] );
println();
}
print( "==" );
println();
}
void kernel_main()
{
heap_init();
paging_init();
screen_init();
process_init();
scheduler_init();
filesystem_init();
// ... //
print( "Welcome to 539kernel!" );
println();
print( "We are now in Protected-mode" );
println();
printi( 539 );
println();
// ... //
char *data = kalloc( 512 );
strcpy( data, "The content of the first file on 539filesystem" );
create_file( "first_file", data );
// ... //
char *data2 = kalloc( 512 );
strcpy( data2, "SECOND FILE in 539filesystem" );
create_file( "second_file", data2 );
// ... //
char *data3 = kalloc( 512 );
strcpy( data3, "THIRD FILE in 539filesystem" );
create_file( "third_file", data3 );
// ... //
char *data4 = kalloc( 512 );
strcpy( data4, "FOURTH FILE in 539filesystem" );
create_file( "fourth_file", data4 );
// ... //
//print_fs();
//delete_file( "first_file" );
//print_fs();
//delete_file( "second_file" );
//print_fs();
//delete_file( "third_file" );
//print_fs();
//delete_file( "fourth_file" );
//print_fs();
// ... //
print( read_file( "first_file" ) ); println();
print( read_file( "second_file" ) ); println();
print( read_file( "third_file" ) ); println();
print( read_file( "fourth_file" ) ); println();
// ... //
/*void *data = //read_disk_chs( 1 );
read_disk( 100 );
printi( data );*/
/*
char *data = kalloc( 512 );
for ( int currIdx = 0; currIdx < 512; currIdx++ )
data[ currIdx ] = 'X';
data[ 511 ] = 'D';
write_disk( 0, data );
char *data2 = kalloc( 512 );
for ( int currIdx = 0; currIdx < 512; currIdx++ )
data2[ currIdx ] = 'Y';
data2[ 511 ] = 'D';
write_disk( 1, data2 );
char *data3 = kalloc( 512 );
for ( int currIdx = 0; currIdx < 512; currIdx++ )
data3[ currIdx ] = 'Z';
data3[ 511 ] = 'D';
write_disk( 2, data3 );
read_disk( 0 );
read_disk( 1 );
read_disk( 2 );
*/
// write_disk_chs( 1, data );
/*
println();
print( "=============" );
*/
/*process_create( &processA );
process_create( &processB );
process_create( &processC );
process_create( &processD );
asm( "sti" );*/
while( 1 );
}
void interrupt_handler( int interrupt_number )
{
print( "Interrupt Received " );
printi( interrupt_number );
println();
}
void processA()
{
print( "Process A," );
while ( 1 )
asm( "mov $5390, %eax" );
}
void processB()
{
print( "Process B," );
while ( 1 )
asm( "mov $5391, %eax" );
}
void processC()
{
print( "Process C," );
while ( 1 )
asm( "mov $5392, %eax" );
}
void processD()
{
print( "Process D," );
while ( 1 )
asm( "mov $5393, %eax" );
}
================================================
FILE: src/paging.c
================================================
#include "paging.h"
void paging_init()
{
// Initializing Kernel's Page Directory (1 to 1 mapping)
unsigned int curr_page_frame = 0;
// We allocate 4 * 1024 bytes here, whatever the size of
// the page directory, to make sure that the page tables
// that are coming next are in page aligned-addresses.
page_directory = kalloc( 4 * 1024 );
for ( int currPDE = 0; currPDE < PDE_NUM; currPDE++ )
{
unsigned int *pagetable = kalloc( 4 * PTE_NUM );
for ( int currPTE = 0; currPTE < PTE_NUM; currPTE++, curr_page_frame++ )
pagetable[ currPTE ] = create_page_entry( curr_page_frame * 4096, 1, 0, 0, 1, 1, 0, 0, 0 );
page_directory[ currPDE ] = create_page_entry( pagetable, 1, 0, 0, 1, 1, 0, 0, 0 );
}
// ... //
load_page_directory();
enable_paging();
}
int create_page_entry( int base_address, char present, char writable, char privilege_level, char cache_enabled, char write_through_cache, char accessed, char page_size, char dirty )
{
int entry = 0;
entry |= present;
entry |= writable << 1;
entry |= privilege_level << 2;
entry |= write_through_cache << 3;
entry |= cache_enabled << 4;
entry |= accessed << 5;
entry |= dirty << 6;
entry |= page_size << 7;
return base_address | entry;
}
================================================
FILE: src/paging.h
================================================
#define PDE_NUM 3
#define PTE_NUM 1024
extern void load_page_directory();
extern void enable_paging();
unsigned int *page_directory;
void paging_init();
int create_page_entry( int, char, char, char, char, char, char, char, char );
================================================
FILE: src/process.c
================================================
#include "process.h"
void process_init()
{
processes_count = 0;
curr_pid = 0;
}
process_t *process_create( int *base_address )
{
process_t *process = kalloc( sizeof( process_t ) );
process->pid = curr_pid++;
process->context.eax = 0;
process->context.ecx = 0;
process->context.edx = 0;
process->context.ebx = 0;
process->context.esp = 0;
process->context.ebp = 0;
process->context.esi = 0;
process->context.edi = 0;
process->context.eip = base_address;
process->state = READY;
process->base_address = base_address;
processes[ process->pid ] = process;
processes_count++;
return process;
}
================================================
FILE: src/process.h
================================================
typedef enum process_state { READY, RUNNING } process_state_t;
typedef struct process_context
{
int eax, ecx, edx, ebx, esp, ebp, esi, edi, eip;
} process_context_t;
typedef struct process
{
int pid;
process_context_t context;
process_state_t state;
int *base_address;
} process_t;
process_t *processes[ 15 ]; // TODO: Dynamic
int processes_count, curr_pid;
void process_init();
process_t *process_create( int * );
================================================
FILE: src/scheduler.c
================================================
#include "scheduler.h"
void scheduler_init()
{
next_sch_pid = 0;
curr_sch_pid = 0;
}
process_t *get_next_process()
{
process_t *next_process = processes[ next_sch_pid ];
curr_sch_pid = next_sch_pid;
next_sch_pid++;
next_sch_pid = next_sch_pid % processes_count;
return next_process;
}
void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, int edx, int ecx, int eax )
{
process_t *curr_process;
print( " EAX = " );
printi( eax );
curr_process = processes[ curr_sch_pid ];
next_process = get_next_process();
// Copy Current Process Context to The Memory
if ( curr_process->state == RUNNING )
{
curr_process->context.eax = eax;
curr_process->context.ecx = ecx;
curr_process->context.edx = edx;
curr_process->context.ebx = ebx;
curr_process->context.esp = esp;
curr_process->context.ebp = ebp;
curr_process->context.esi = esi;
curr_process->context.edi = edi;
curr_process->context.eip = eip;
}
curr_process->state = READY;
// ... //
// Copy Next Process Context to The Processor
// TODO: In Memory-Management Version. Copy ESP and EBP
asm( " mov %0, %%eax; \
mov %0, %%ecx; \
mov %0, %%edx; \
mov %0, %%ebx; \
mov %0, %%esi; \
mov %0, %%edi;"
: : "r" ( next_process->context.eax ), "r" ( next_process->context.ecx ), "r" ( next_process->context.edx ), "r" ( next_process->context.ebx ),
"r" ( next_process->context.esi ), "r" ( next_process->context.edi ) );
next_process->state = RUNNING;
}
void run_next_process()
{
// No code should reside here at all. Otherwise,
// we will not be sure that the context of the process
// to run will be correct.
asm( " sti; \
jmp *%0" : : "r" ( next_process->context.eip ) );
}
================================================
FILE: src/scheduler.h
================================================
#include "process.h"
int next_sch_pid, curr_sch_pid;
process_t *next_process;
void scheduler_init();
process_t *get_next_process();
void scheduler( int, int, int, int, int, int, int, int, int );
void run_next_process();
================================================
FILE: src/screen.c
================================================
#include "screen.h"
void screen_init()
{
// VGA Text Mode = 0xB8000
// VGA Graphics Mode = 0xA0000
video = 0xB8000;
nextTextPos = 0;
currLine = 0;
}
void print( char *str )
{
int currCharLocationInVidMem, currColorLocationInVidMem;
while ( *str != '\0' )
{
currCharLocationInVidMem = nextTextPos * 2;
currColorLocationInVidMem = currCharLocationInVidMem + 1;
video[ currCharLocationInVidMem ] = *str;
video[ currColorLocationInVidMem ] = 15;
nextTextPos++;
str++;
}
}
void println()
{
if ( currLine > 23 )
{
cls();
return;
}
nextTextPos = ++currLine * 80;
}
void printi( int number )
{
char* digitToStr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
if ( number >= 0 && number <= 9 )
{
print( digitToStr[ number ] );
return;
}
else
{
int remaining = number % 10;
number = number / 10;
printi( number );
printi( remaining );
}
}
void cls()
{
for ( int currPos = 0; currPos < 3999; currPos = currPos + 2 )
{
video[ currPos ] = 0;
video[ currPos + 1 ] = 0;
}
nextTextPos = 0;
currLine = 0;
}
================================================
FILE: src/screen.h
================================================
volatile unsigned char *video;
int nextTextPos;
int currLine;
void screen_init();
void print( char * );
void println();
void printi( int );
void cls();
================================================
FILE: src/simple_kernel.asm
================================================
start:
mov ax, cs
mov ds, ax
; --- ;
mov si, hello_string
call print_string
jmp $
print_string:
mov ah, 0Eh
print_char:
lodsb
cmp al, 0
je done
int 10h
jmp print_char
done:
ret
hello_string db 'Hello World!, From Simple Assembly 539kernel!', 0
================================================
FILE: src/starter.asm
================================================
bits 16
extern kernel_main
extern interrupt_handler
extern scheduler
extern run_next_process
extern page_directory
global load_page_directory
global enable_paging
global dev_write
global dev_write_word
global dev_read
start:
mov ax, cs
mov ds, ax
; --- ;
call load_gdt
call init_video_mode
call enter_protected_mode
call setup_interrupts
call load_task_register
; --- ;
call 08h:start_kernel
load_gdt:
cli
lgdt [gdtr - start]
ret
setup_interrupts:
call remap_pic
call load_idt
ret
init_video_mode:
;; Set Video Mode
mov ah, 0h
mov al, 03h ; 03h For Text Mode. 13h For Graphics Mode.
int 10h
;; Disable Text Cursor
mov ah, 01h
mov cx, 2000h
int 10h
ret
enter_protected_mode:
mov eax, cr0
or eax, 1
mov cr0, eax
ret
remap_pic:
mov al, 11h
send_init_cmd_to_pic_master:
out 0x20, al
send_init_cmd_to_pic_slave:
out 0xa0, al
; ... ;
make_irq_starts_from_intr_32_in_pic_master:
mov al, 32d
out 0x21, al
make_irq_starts_from_intr_40_in_pic_slave:
mov al, 40d
out 0xa1, al
; ... ;
tell_pic_master_where_pic_slave_is_connected:
mov al, 04h
out 0x21, al
tell_pic_slave_where_pic_master_is_connected:
mov al, 02h
out 0xa1, al
; ... ;
mov al, 01h
tell_pic_master_the_arch_is_x86:
out 0x21, al
tell_pic_slave_the_arch_is_x86:
out 0xa1, al
; ... ;
mov al, 0h
make_pic_master_enables_all_irqs:
out 0x21, al
make_pic_slave_enables_all_irqs:
out 0xa1, al
; ... ;
ret
load_idt:
lidt [idtr - start]
ret
load_task_register:
mov ax, 40d
ltr ax
ret
bits 32
load_page_directory:
mov eax, [page_directory]
mov cr3, eax
ret
enable_paging:
mov eax, cr0
or eax, 80000000h
mov cr0, eax
ret
; --- ;
; dev_write( int port, int cmd );
dev_write:
push edx
push eax
xor edx, edx
xor eax, eax
mov dx, [esp + 12]
mov al, [esp + 16]
out dx, al
pop eax
pop edx
ret
dev_write_word:
push edx
push eax
xor edx, edx
xor eax, eax
mov dx, [esp + 12]
mov ax, [esp + 16]
out dx, ax
pop eax
pop edx
ret
; dev_read( int port );
dev_read:
push edx
xor edx, edx
xor eax, eax
mov dx, [esp + 8]
in ax, dx
;jmp $
pop edx
ret
start_kernel:
mov eax, 10h
mov ds, eax
mov ss, eax
mov es, eax
mov eax, 0h
mov fs, eax
mov gs, eax
;sti ; TODO: I think we need to enable it. Does the multitasking work? 13 Nov 2022. Check if we enabled interrupts elsewhere?
call kernel_main
%include "gdt.asm"
%include "idt.asm"
tss:
dd 0
================================================
FILE: src/str.c
================================================
#include "str.h"
void strcpy( char *dest, char *src )
{
int idx = 0;
while ( *src != '\0' )
{
dest[ idx ] = *src;
src++;
idx++;
}
}
int strcmp( char *str1, char *str2 )
{
while ( *str1 != '\0' )
{
if ( *str1 != *str2 )
return 0;
str1++;
str2++;
}
if ( *str2 != '\0' )
return 0;
return 1;
}
================================================
FILE: src/str.h
================================================
void strcpy( char *, char * );
int strcmp( char *, char * );
gitextract_ir_g73hk/
├── README.md
├── evolution_by_versions/
│ ├── .gitignore
│ ├── 01_539kernel_bootloader/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ └── simple_kernel.asm
│ ├── 03_539kernel_progenitor/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ └── starter.asm
│ ├── 04_539kernel_version_t/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ ├── process.c
│ │ ├── process.h
│ │ ├── scheduler.c
│ │ ├── scheduler.h
│ │ ├── screen.c
│ │ ├── screen.h
│ │ └── starter.asm
│ ├── 05_539kernel_version_g/
│ │ ├── Makefile
│ │ ├── bootstrap.asm
│ │ ├── gdt.asm
│ │ ├── heap.c
│ │ ├── heap.h
│ │ ├── idt.asm
│ │ ├── linker.ld
│ │ ├── main.c
│ │ ├── paging.c
│ │ ├── paging.h
│ │ ├── process.c
│ │ ├── process.h
│ │ ├── scheduler.c
│ │ ├── scheduler.h
│ │ ├── screen.c
│ │ ├── screen.h
│ │ └── starter.asm
│ └── 06_539kernel_version_ne/
│ ├── Makefile
│ ├── ata.c
│ ├── ata.h
│ ├── bochs
│ ├── bootstrap.asm
│ ├── filesystem.c
│ ├── filesystem.h
│ ├── gdt.asm
│ ├── heap.c
│ ├── heap.h
│ ├── idt.asm
│ ├── linker.ld
│ ├── main.c
│ ├── paging.c
│ ├── paging.h
│ ├── process.c
│ ├── process.h
│ ├── scheduler.c
│ ├── scheduler.h
│ ├── screen.c
│ ├── screen.h
│ ├── starter.asm
│ ├── str.c
│ └── str.h
└── src/
├── .gitignore
├── Makefile
├── README
├── ata.c
├── ata.h
├── bochs
├── bootstrap.asm
├── filesystem.c
├── filesystem.h
├── gdt.asm
├── heap.c
├── heap.h
├── idt.asm
├── linker.ld
├── main.c
├── paging.c
├── paging.h
├── process.c
├── process.h
├── scheduler.c
├── scheduler.h
├── screen.c
├── screen.h
├── simple_kernel.asm
├── starter.asm
├── str.c
└── str.h
SYMBOL INDEX (126 symbols across 35 files)
FILE: evolution_by_versions/03_539kernel_progenitor/main.c
function kernel_main (line 10) | void kernel_main()
function interrupt_handler (line 22) | void interrupt_handler( int interrupt_number )
function print (line 29) | void print( char *str )
function println (line 47) | void println()
function printi (line 52) | void printi( int number )
FILE: evolution_by_versions/04_539kernel_version_t/main.c
function kernel_main (line 9) | void kernel_main()
function interrupt_handler (line 32) | void interrupt_handler( int interrupt_number )
function processA (line 39) | void processA()
function processB (line 47) | void processB()
function processC (line 55) | void processC()
function processD (line 63) | void processD()
FILE: evolution_by_versions/04_539kernel_version_t/process.c
function process_init (line 3) | void process_init()
function process_create (line 9) | void process_create( int *base_address, process_t *process )
FILE: evolution_by_versions/04_539kernel_version_t/process.h
type process_state_t (line 1) | typedef enum process_state { READY, RUNNING } process_state_t;
type process_context_t (line 3) | typedef struct process_context
type process_t (line 8) | typedef struct process
FILE: evolution_by_versions/04_539kernel_version_t/scheduler.c
function scheduler_init (line 3) | void scheduler_init()
function process_t (line 9) | process_t *get_next_process()
function scheduler (line 20) | void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, in...
function run_next_process (line 69) | void run_next_process()
FILE: evolution_by_versions/04_539kernel_version_t/screen.c
function screen_init (line 3) | void screen_init()
function print (line 10) | void print( char *str )
function println (line 28) | void println()
function printi (line 33) | void printi( int number )
FILE: evolution_by_versions/05_539kernel_version_g/heap.c
function heap_init (line 3) | void heap_init()
function kalloc (line 8) | int kalloc( int bytes )
FILE: evolution_by_versions/05_539kernel_version_g/main.c
function kernel_main (line 10) | void kernel_main()
function interrupt_handler (line 33) | void interrupt_handler( int interrupt_number )
function processA (line 40) | void processA()
function processB (line 48) | void processB()
function processC (line 56) | void processC()
function processD (line 64) | void processD()
FILE: evolution_by_versions/05_539kernel_version_g/paging.c
function create_page_entry (line 3) | int create_page_entry( int base_address, char present, char writable, ch...
function paging_init (line 19) | void paging_init()
FILE: evolution_by_versions/05_539kernel_version_g/process.c
function process_init (line 3) | void process_init()
function process_t (line 9) | process_t *process_create( int *base_address )
FILE: evolution_by_versions/05_539kernel_version_g/process.h
type process_state_t (line 1) | typedef enum process_state { READY, RUNNING } process_state_t;
type process_context_t (line 3) | typedef struct process_context
type process_t (line 8) | typedef struct process
FILE: evolution_by_versions/05_539kernel_version_g/scheduler.c
function scheduler_init (line 3) | void scheduler_init()
function process_t (line 9) | process_t *get_next_process()
function scheduler (line 20) | void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, in...
function run_next_process (line 69) | void run_next_process()
FILE: evolution_by_versions/05_539kernel_version_g/screen.c
function screen_init (line 3) | void screen_init()
function print (line 10) | void print( char *str )
function println (line 28) | void println()
function printi (line 33) | void printi( int number )
FILE: evolution_by_versions/06_539kernel_version_ne/ata.c
function wait_drive_until_ready (line 3) | void wait_drive_until_ready()
function write_disk_chs (line 64) | void write_disk_chs( int sector, short *buffer )
function write_disk (line 81) | void write_disk( int address, short *buffer )
FILE: evolution_by_versions/06_539kernel_version_ne/filesystem.c
function filesystem_init (line 3) | void filesystem_init()
function create_file (line 8) | void create_file( char *filename, char *buffer )
function delete_file (line 93) | void delete_file( char *filename )
function update_base_block (line 136) | void update_base_block( int new_head, int new_tail )
function metadata_t (line 144) | metadata_t *load_metadata( int address )
function get_address_by_filename (line 151) | int get_address_by_filename( char *filename )
function get_prev_file_address (line 173) | int get_prev_file_address( int address )
function get_files_number (line 190) | int get_files_number()
FILE: evolution_by_versions/06_539kernel_version_ne/filesystem.h
type base_block_t (line 4) | typedef struct
type metadata_t (line 9) | typedef struct
FILE: evolution_by_versions/06_539kernel_version_ne/heap.c
function heap_init (line 3) | void heap_init()
function kalloc (line 8) | int kalloc( int bytes )
FILE: evolution_by_versions/06_539kernel_version_ne/main.c
function kernel_main (line 12) | void kernel_main()
function print_fs (line 68) | void print_fs()
function interrupt_handler (line 83) | void interrupt_handler( int interrupt_number )
function processA (line 90) | void processA()
function processB (line 98) | void processB()
function processC (line 106) | void processC()
function processD (line 114) | void processD()
FILE: evolution_by_versions/06_539kernel_version_ne/paging.c
function create_page_entry (line 3) | int create_page_entry( int base_address, char present, char writable, ch...
function paging_init (line 19) | void paging_init()
FILE: evolution_by_versions/06_539kernel_version_ne/process.c
function process_init (line 3) | void process_init()
function process_t (line 9) | process_t *process_create( int *base_address )
FILE: evolution_by_versions/06_539kernel_version_ne/process.h
type process_state_t (line 1) | typedef enum process_state { READY, RUNNING } process_state_t;
type process_context_t (line 3) | typedef struct process_context
type process_t (line 8) | typedef struct process
FILE: evolution_by_versions/06_539kernel_version_ne/scheduler.c
function scheduler_init (line 3) | void scheduler_init()
function process_t (line 9) | process_t *get_next_process()
function scheduler (line 20) | void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, in...
function run_next_process (line 69) | void run_next_process()
FILE: evolution_by_versions/06_539kernel_version_ne/screen.c
function screen_init (line 3) | void screen_init()
function print (line 10) | void print( char *str )
function println (line 28) | void println()
function printi (line 33) | void printi( int number )
FILE: evolution_by_versions/06_539kernel_version_ne/str.c
function strcpy (line 3) | void strcpy( char *dest, char *src )
function strcmp (line 16) | int strcmp( char *str1, char *str2 )
FILE: src/ata.c
function wait_drive_until_ready (line 3) | void wait_drive_until_ready()
function write_disk (line 38) | void write_disk( int address, short *buffer )
function write_disk_chs (line 79) | void write_disk_chs( int sector, short *buffer )
FILE: src/filesystem.c
function filesystem_init (line 3) | void filesystem_init()
function update_base_block (line 8) | void update_base_block( int new_head, int new_tail )
function metadata_t (line 16) | metadata_t *load_metadata( int address )
function get_files_number (line 23) | int get_files_number()
function create_file (line 47) | void create_file( char *filename, char *buffer )
function get_address_by_filename (line 115) | int get_address_by_filename( char *filename )
function get_prev_file_address (line 151) | int get_prev_file_address( int address )
function delete_file (line 168) | void delete_file( char *filename )
FILE: src/filesystem.h
type base_block_t (line 4) | typedef struct
type metadata_t (line 9) | typedef struct
FILE: src/heap.c
function heap_init (line 3) | void heap_init()
function kalloc (line 8) | int kalloc( int bytes )
FILE: src/main.c
function print_fs (line 14) | void print_fs()
function kernel_main (line 29) | void kernel_main()
function interrupt_handler (line 156) | void interrupt_handler( int interrupt_number )
function processA (line 163) | void processA()
function processB (line 171) | void processB()
function processC (line 179) | void processC()
function processD (line 187) | void processD()
FILE: src/paging.c
function paging_init (line 3) | void paging_init()
function create_page_entry (line 30) | int create_page_entry( int base_address, char present, char writable, ch...
FILE: src/process.c
function process_init (line 3) | void process_init()
function process_t (line 9) | process_t *process_create( int *base_address )
FILE: src/process.h
type process_state_t (line 1) | typedef enum process_state { READY, RUNNING } process_state_t;
type process_context_t (line 3) | typedef struct process_context
type process_t (line 8) | typedef struct process
FILE: src/scheduler.c
function scheduler_init (line 3) | void scheduler_init()
function process_t (line 9) | process_t *get_next_process()
function scheduler (line 20) | void scheduler( int eip, int edi, int esi, int ebp, int esp, int ebx, in...
function run_next_process (line 62) | void run_next_process()
FILE: src/screen.c
function screen_init (line 3) | void screen_init()
function print (line 12) | void print( char *str )
function println (line 30) | void println()
function printi (line 41) | void printi( int number )
function cls (line 60) | void cls()
FILE: src/str.c
function strcpy (line 3) | void strcpy( char *dest, char *src )
function strcmp (line 16) | int strcmp( char *str1, char *str2 )
Condensed preview — 93 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (123K chars).
[
{
"path": "README.md",
"chars": 417,
"preview": "539kernel is a simple x86 32bit educational kernel which has been written especially for the book \"**[A Journey in Creat"
},
{
"path": "evolution_by_versions/.gitignore",
"chars": 588,
"preview": "\n# Created by https://www.gitignore.io/api/c\n# Edit at https://www.gitignore.io/?templates=c\n\n### C ###\n# Prerequisites\n"
},
{
"path": "evolution_by_versions/01_539kernel_bootloader/Makefile",
"chars": 346,
"preview": "ASM = nasm\nBOOTSTRAP_FILE = bootstrap.asm \nKERNEL_FILE = simple_kernel.asm\n\nbuild: $(BOOTSTRAP_FILE) $(KERNEL_FILE)\n\t$(A"
},
{
"path": "evolution_by_versions/01_539kernel_bootloader/bootstrap.asm",
"chars": 972,
"preview": "start:\n\tmov ax, 07C0h\n\tmov ds, ax\n\t\n\tmov si, title_string\n\tcall print_string\n\t\n\tmov si, message_string\n\tcall print_strin"
},
{
"path": "evolution_by_versions/01_539kernel_bootloader/simple_kernel.asm",
"chars": 273,
"preview": "start:\n\tmov ax, cs\n\tmov ds, ax\n\n\t; --- ;\n\t\n\tmov si, hello_string\n\tcall print_string\n\t\n\tjmp $\n\nprint_string:\n\tmov ah, 0Eh"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/Makefile",
"chars": 730,
"preview": "ASM = nasm\nCC = gcc\nBOOTSTRAP_FILE = bootstrap.asm \nINIT_KERNEL_FILES = starter.asm\nKERNEL_FILES = main.c\nKERNEL_FLAGS ="
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/bootstrap.asm",
"chars": 1266,
"preview": "start:\n\tmov ax, 07C0h\n\tmov ds, ax\n\t\n\tmov si, title_string\n\tcall print_string\n\t\n\tmov si, message_string\n\tcall print_strin"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/gdt.asm",
"chars": 365,
"preview": "gdt:\n\tnull_descriptor\t\t\t\t: \tdw 0, 0, 0, 0\n\tkernel_code_descriptor\t\t: \tdw 0xffff, 0x0000, 0x9a00, 0x00cf\n\tkernel_data_des"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/idt.asm",
"chars": 3680,
"preview": "isr_0:\n\tcli\n\tpush 0\n\tjmp isr_basic\n\nisr_1:\n\tcli\n\tpush 1\n\tjmp isr_basic\n\t\nisr_2:\n\tcli\n\tpush 2\n\tjmp isr_basic\n\t\nisr_3:\n\tcl"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/linker.ld",
"chars": 362,
"preview": "/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */\n\nSECTIONS\n{\n .text 0x09000 :\n {"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/main.c",
"chars": 1145,
"preview": "volatile unsigned char *video = 0xB8000;\n\nint nextTextPos = 0;\nint currLine = 0;\n\nvoid print( char * );\nvoid println();\n"
},
{
"path": "evolution_by_versions/03_539kernel_progenitor/starter.asm",
"chars": 1430,
"preview": "bits 16\nextern kernel_main\nextern interrupt_handler\n\nstart:\n\tmov ax, cs\n\tmov ds, ax\n\t\t\n\tcall load_gdt\n\tcall init_video_m"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/Makefile",
"chars": 913,
"preview": "ASM = nasm\nCC = gcc\nBOOTSTRAP_FILE = bootstrap.asm \nINIT_KERNEL_FILES = starter.asm\nKERNEL_FILES = main.c\nKERNEL_FLAGS ="
},
{
"path": "evolution_by_versions/04_539kernel_version_t/bootstrap.asm",
"chars": 1266,
"preview": "start:\n\tmov ax, 07C0h\n\tmov ds, ax\n\t\n\tmov si, title_string\n\tcall print_string\n\t\n\tmov si, message_string\n\tcall print_strin"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/gdt.asm",
"chars": 419,
"preview": "gdt:\n\tnull_descriptor\t\t\t\t: \tdw 0, 0, 0, 0\n\tkernel_code_descriptor\t\t: \tdw 0xffff, 0x0000, 0x9a00, 0x00cf\n\tkernel_data_des"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/idt.asm",
"chars": 3971,
"preview": "isr_0:\n\tcli\n\tpush 0\n\tjmp isr_basic\n\nisr_1:\n\tcli\n\tpush 1\n\tjmp isr_basic\n\t\nisr_2:\n\tcli\n\tpush 2\n\tjmp isr_basic\n\t\nisr_3:\n\tcl"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/linker.ld",
"chars": 362,
"preview": "/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */\n\nSECTIONS\n{\n .text 0x09000 :\n {"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/main.c",
"chars": 1039,
"preview": "#include \"screen.h\"\n#include \"scheduler.h\"\n\nvoid processA();\nvoid processB();\nvoid processC();\nvoid processD();\n\nvoid ke"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/process.c",
"chars": 624,
"preview": "#include \"process.h\"\n\nvoid process_init()\n{\n processes_count = 0;\n curr_pid = 0;\n}\n\nvoid process_create( int *base"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/process.h",
"chars": 430,
"preview": "typedef enum process_state { READY, RUNNING } process_state_t;\n\ntypedef struct process_context\n{\n int eax, ecx, edx, "
},
{
"path": "evolution_by_versions/04_539kernel_version_t/scheduler.c",
"chars": 1806,
"preview": "#include \"scheduler.h\"\n\nvoid scheduler_init()\n{\n next_sch_pid = 0;\n curr_sch_pid = 0;\n}\n\nprocess_t *get_next_proce"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/scheduler.h",
"chars": 223,
"preview": "#include \"process.h\"\n\nint next_sch_pid, curr_sch_pid;\n\nprocess_t *next_process;\n\nvoid scheduler_init();\nprocess_t *get_n"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/screen.c",
"chars": 815,
"preview": "#include \"screen.h\"\n\nvoid screen_init()\n{\n video = 0xB8000;\n nextTextPos = 0;\n currLine = 0;\n}\n\nvoid print( cha"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/screen.h",
"chars": 142,
"preview": "volatile unsigned char *video;\n\nint nextTextPos;\nint currLine;\n\nvoid screen_init();\nvoid print( char * );\nvoid println()"
},
{
"path": "evolution_by_versions/04_539kernel_version_t/starter.asm",
"chars": 1576,
"preview": "bits 16\nextern kernel_main\nextern interrupt_handler\nextern scheduler\nextern run_next_process\n\nstart:\n\tmov ax, cs\n\tmov ds"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/Makefile",
"chars": 1055,
"preview": "ASM = nasm\nCC = gcc\nBOOTSTRAP_FILE = bootstrap.asm \nSIMPLE_KERNEL = simple_kernel.asm\nINIT_KERNEL_FILES = starter.asm\nKE"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/bootstrap.asm",
"chars": 1266,
"preview": "start:\n\tmov ax, 07C0h\n\tmov ds, ax\n\t\n\tmov si, title_string\n\tcall print_string\n\t\n\tmov si, message_string\n\tcall print_strin"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/gdt.asm",
"chars": 419,
"preview": "gdt:\n\tnull_descriptor\t\t\t\t: \tdw 0, 0, 0, 0\n\tkernel_code_descriptor\t\t: \tdw 0xffff, 0x0000, 0x9a00, 0x00cf\n\tkernel_data_des"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/heap.c",
"chars": 191,
"preview": "#include \"heap.h\"\n\nvoid heap_init()\n{\n\theap_base = 0x100000;\n}\n\nint kalloc( int bytes )\n{\n\tunsigned int new_object_addre"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/heap.h",
"chars": 62,
"preview": "unsigned int heap_base;\n\nvoid heap_init();\nint kalloc( int );\n"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/idt.asm",
"chars": 3971,
"preview": "isr_0:\n\tcli\n\tpush 0\n\tjmp isr_basic\n\nisr_1:\n\tcli\n\tpush 1\n\tjmp isr_basic\n\t\nisr_2:\n\tcli\n\tpush 2\n\tjmp isr_basic\n\t\nisr_3:\n\tcl"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/linker.ld",
"chars": 362,
"preview": "/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */\n\nSECTIONS\n{\n .text 0x09000 :\n {"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/main.c",
"chars": 1030,
"preview": "#include \"screen.h\"\n#include \"scheduler.h\"\n#include \"heap.h\"\n\nvoid processA();\nvoid processB();\nvoid processC();\nvoid pr"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/paging.c",
"chars": 1053,
"preview": "#include \"paging.h\"\n\nint create_page_entry( int base_address, char present, char writable, char privilege_level, char ca"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/paging.h",
"chars": 234,
"preview": "#define PDE_NUM 3\n#define PTE_NUM 1024\n\nextern void load_page_directory();\nextern void enable_paging();\n\nunsigned int *p"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/process.c",
"chars": 662,
"preview": "#include \"process.h\"\n\nvoid process_init()\n{\n processes_count = 0;\n curr_pid = 0;\n}\n\nprocess_t *process_create( int"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/process.h",
"chars": 423,
"preview": "typedef enum process_state { READY, RUNNING } process_state_t;\n\ntypedef struct process_context\n{\n int eax, ecx, edx, "
},
{
"path": "evolution_by_versions/05_539kernel_version_g/scheduler.c",
"chars": 1806,
"preview": "#include \"scheduler.h\"\n\nvoid scheduler_init()\n{\n next_sch_pid = 0;\n curr_sch_pid = 0;\n}\n\nprocess_t *get_next_proce"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/scheduler.h",
"chars": 223,
"preview": "#include \"process.h\"\n\nint next_sch_pid, curr_sch_pid;\n\nprocess_t *next_process;\n\nvoid scheduler_init();\nprocess_t *get_n"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/screen.c",
"chars": 815,
"preview": "#include \"screen.h\"\n\nvoid screen_init()\n{\n video = 0xB8000;\n nextTextPos = 0;\n currLine = 0;\n}\n\nvoid print( cha"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/screen.h",
"chars": 142,
"preview": "volatile unsigned char *video;\n\nint nextTextPos;\nint currLine;\n\nvoid screen_init();\nvoid print( char * );\nvoid println()"
},
{
"path": "evolution_by_versions/05_539kernel_version_g/starter.asm",
"chars": 1789,
"preview": "bits 16\nextern kernel_main\nextern interrupt_handler\nextern scheduler\nextern run_next_process\nextern page_directory\n\nglob"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/Makefile",
"chars": 1248,
"preview": "ASM = nasm\nCC = gcc\nBOOTSTRAP_FILE = bootstrap.asm \nSIMPLE_KERNEL = simple_kernel.asm\nINIT_KERNEL_FILES = starter.asm\nKE"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/ata.c",
"chars": 2287,
"preview": "#include \"ata.h\"\n\nvoid wait_drive_until_ready()\n{\n\tint status = 0;\n\t\n\tdo\n\t{\n\t\tstatus = dev_read( BASE_PORT + 7 );\n\t} whi"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/ata.h",
"chars": 204,
"preview": "#define BASE_PORT 0x1F0\n#define SECTOR_SIZE 512\n\nvoid wait_drive_until_ready();\n\nvoid *read_disk( int );\nvoid write_disk"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/bochs",
"chars": 1064,
"preview": "plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, gameport=1, iodebug=1\nconfig_interface"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/bootstrap.asm",
"chars": 1266,
"preview": "start:\n\tmov ax, 07C0h\n\tmov ds, ax\n\t\n\tmov si, title_string\n\tcall print_string\n\t\n\tmov si, message_string\n\tcall print_strin"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/filesystem.c",
"chars": 4023,
"preview": "#include \"filesystem.h\"\n\nvoid filesystem_init()\n{\n\tbase_block = read_disk( BASE_BLOCK_ADDRESS );\n}\n\nvoid create_file( ch"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/filesystem.h",
"chars": 492,
"preview": "#define BASE_BLOCK_ADDRESS 100\n#define FILENAME_LENGTH 256\n\ntypedef struct\n{\n\tint head, tail;\n} base_block_t;\n\ntypedef s"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/gdt.asm",
"chars": 419,
"preview": "gdt:\n\tnull_descriptor\t\t\t\t: \tdw 0, 0, 0, 0\n\tkernel_code_descriptor\t\t: \tdw 0xffff, 0x0000, 0x9a00, 0x00cf\n\tkernel_data_des"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/heap.c",
"chars": 191,
"preview": "#include \"heap.h\"\n\nvoid heap_init()\n{\n\theap_base = 0x100000;\n}\n\nint kalloc( int bytes )\n{\n\tunsigned int new_object_addre"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/heap.h",
"chars": 62,
"preview": "unsigned int heap_base;\n\nvoid heap_init();\nint kalloc( int );\n"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/idt.asm",
"chars": 3971,
"preview": "isr_0:\n\tcli\n\tpush 0\n\tjmp isr_basic\n\nisr_1:\n\tcli\n\tpush 1\n\tjmp isr_basic\n\t\nisr_2:\n\tcli\n\tpush 2\n\tjmp isr_basic\n\t\nisr_3:\n\tcl"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/linker.ld",
"chars": 362,
"preview": "/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */\n\nSECTIONS\n{\n .text 0x09000 :\n {"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/main.c",
"chars": 1946,
"preview": "#include \"screen.h\"\n#include \"scheduler.h\"\n#include \"heap.h\"\n\nvoid processA();\nvoid processB();\nvoid processC();\nvoid pr"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/paging.c",
"chars": 1053,
"preview": "#include \"paging.h\"\n\nint create_page_entry( int base_address, char present, char writable, char privilege_level, char ca"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/paging.h",
"chars": 234,
"preview": "#define PDE_NUM 3\n#define PTE_NUM 1024\n\nextern void load_page_directory();\nextern void enable_paging();\n\nunsigned int *p"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/process.c",
"chars": 662,
"preview": "#include \"process.h\"\n\nvoid process_init()\n{\n processes_count = 0;\n curr_pid = 0;\n}\n\nprocess_t *process_create( int"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/process.h",
"chars": 423,
"preview": "typedef enum process_state { READY, RUNNING } process_state_t;\n\ntypedef struct process_context\n{\n int eax, ecx, edx, "
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/scheduler.c",
"chars": 1806,
"preview": "#include \"scheduler.h\"\n\nvoid scheduler_init()\n{\n next_sch_pid = 0;\n curr_sch_pid = 0;\n}\n\nprocess_t *get_next_proce"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/scheduler.h",
"chars": 223,
"preview": "#include \"process.h\"\n\nint next_sch_pid, curr_sch_pid;\n\nprocess_t *next_process;\n\nvoid scheduler_init();\nprocess_t *get_n"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/screen.c",
"chars": 815,
"preview": "#include \"screen.h\"\n\nvoid screen_init()\n{\n video = 0xB8000;\n nextTextPos = 0;\n currLine = 0;\n}\n\nvoid print( cha"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/screen.h",
"chars": 142,
"preview": "volatile unsigned char *video;\n\nint nextTextPos;\nint currLine;\n\nvoid screen_init();\nvoid print( char * );\nvoid println()"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/starter.asm",
"chars": 2320,
"preview": "bits 16\nextern kernel_main\nextern interrupt_handler\nextern scheduler\nextern run_next_process\nextern page_directory\n\nglob"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/str.c",
"chars": 330,
"preview": "#include \"str.h\"\n\nvoid strcpy( char *dest, char *src )\n{\n\tint idx = 0;\n\t\n\twhile ( *src != '\\0' )\n\t{\n\t\tdest[ idx ] = *src"
},
{
"path": "evolution_by_versions/06_539kernel_version_ne/str.h",
"chars": 61,
"preview": "void strcpy( char *, char * );\nint strcmp( char *, char * );\n"
},
{
"path": "src/.gitignore",
"chars": 588,
"preview": "\n# Created by https://www.gitignore.io/api/c\n# Edit at https://www.gitignore.io/?templates=c\n\n### C ###\n# Prerequisites\n"
},
{
"path": "src/Makefile",
"chars": 4116,
"preview": "ASM = nasm\nCC = gcc\nBOOTSTRAP_FILE = bootstrap.asm \nSIMPLE_KERNEL = simple_kernel.asm\nINIT_KERNEL_FILES = starter.asm\nKE"
},
{
"path": "src/README",
"chars": 131,
"preview": "[MQH] 25 Nov 2019\nHere is the final code of 539kernel. Any incremental steps, examples and excercises can be found in .."
},
{
"path": "src/ata.c",
"chars": 2787,
"preview": "#include \"ata.h\"\n\nvoid wait_drive_until_ready()\n{\n\tint status = 0;\n\t\n\tdo\n\t{\n\t\tstatus = dev_read( BASE_PORT + 7 );\n\t} whi"
},
{
"path": "src/ata.h",
"chars": 204,
"preview": "#define BASE_PORT 0x1F0\n#define SECTOR_SIZE 512\n\nvoid wait_drive_until_ready();\n\nvoid *read_disk( int );\nvoid write_disk"
},
{
"path": "src/bochs",
"chars": 1813,
"preview": "# configuration file generated by Bochs\nplugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1"
},
{
"path": "src/bootstrap.asm",
"chars": 7745,
"preview": "start:\n\t; [MQH] 3 Sep 2019\n\t; When a the boot sector is loaded by BIOS. It will be loaded on the location 07C0h in the m"
},
{
"path": "src/filesystem.c",
"chars": 3949,
"preview": "#include \"filesystem.h\"\n\nvoid filesystem_init()\n{\n\tbase_block = read_disk( BASE_BLOCK_ADDRESS );\n}\n\nvoid update_base_blo"
},
{
"path": "src/filesystem.h",
"chars": 492,
"preview": "#define BASE_BLOCK_ADDRESS 100\n#define FILENAME_LENGTH 256\n\ntypedef struct\n{\n\tint head, tail;\n} base_block_t;\n\ntypedef s"
},
{
"path": "src/gdt.asm",
"chars": 613,
"preview": "; The values of the decriptors from Basekernel (kernelcode.S) (https://github.com/dthain/basekernel)\ngdt:\n\tnull_descript"
},
{
"path": "src/heap.c",
"chars": 232,
"preview": "#include \"heap.h\"\n\nvoid heap_init()\n{\n\theap_base = 0x100000;\n}\n\nint kalloc( int bytes )\n{\n\t// Note: Not necessarily page"
},
{
"path": "src/heap.h",
"chars": 62,
"preview": "unsigned int heap_base;\n\nvoid heap_init();\nint kalloc( int );\n"
},
{
"path": "src/idt.asm",
"chars": 4110,
"preview": "isr_0:\n\tcli\n\tpush 0\n\tjmp isr_basic\n\nisr_1:\n\tcli\n\tpush 1\n\tjmp isr_basic\n\t\nisr_2:\n\tcli\n\tpush 2\n\tjmp isr_basic\n\t\nisr_3:\n\tcl"
},
{
"path": "src/linker.ld",
"chars": 438,
"preview": "/* Based on: http://www.jamesmolloy.co.uk/tutorial_html/1.-Environment%20setup.html */\n\nSECTIONS\n{\n .text 0x09000 :\n {"
},
{
"path": "src/main.c",
"chars": 3038,
"preview": "#include \"heap.h\"\n#include \"paging.h\"\n#include \"screen.h\"\n#include \"scheduler.h\"\n#include \"ata.h\"\n#include \"filesystem.h"
},
{
"path": "src/paging.c",
"chars": 1238,
"preview": "#include \"paging.h\"\n\nvoid paging_init()\n{\n\t// Initializing Kernel's Page Directory (1 to 1 mapping)\n\t\n\tunsigned int curr"
},
{
"path": "src/paging.h",
"chars": 234,
"preview": "#define PDE_NUM 3\n#define PTE_NUM 1024\n\nextern void load_page_directory();\nextern void enable_paging();\n\nunsigned int *p"
},
{
"path": "src/process.c",
"chars": 623,
"preview": "#include \"process.h\"\n\nvoid process_init()\n{\n\tprocesses_count = 0;\n\tcurr_pid = 0;\n}\n\nprocess_t *process_create( int *base"
},
{
"path": "src/process.h",
"chars": 424,
"preview": "typedef enum process_state { READY, RUNNING } process_state_t;\n\ntypedef struct process_context\n{\n\tint eax, ecx, edx, ebx"
},
{
"path": "src/scheduler.c",
"chars": 1725,
"preview": "#include \"scheduler.h\"\n\nvoid scheduler_init()\n{\n\tnext_sch_pid = 0;\n\tcurr_sch_pid = 0;\n}\n\nprocess_t *get_next_process()\n{"
},
{
"path": "src/scheduler.h",
"chars": 223,
"preview": "#include \"process.h\"\n\nint next_sch_pid, curr_sch_pid;\n\nprocess_t *next_process;\n\nvoid scheduler_init();\nprocess_t *get_n"
},
{
"path": "src/screen.c",
"chars": 1085,
"preview": "#include \"screen.h\"\n\nvoid screen_init()\n{\n\t// VGA Text Mode = 0xB8000\n\t// VGA Graphics Mode = 0xA0000\n\tvideo = 0xB8000;\n"
},
{
"path": "src/screen.h",
"chars": 154,
"preview": "volatile unsigned char *video;\n\nint nextTextPos;\nint currLine;\n\nvoid screen_init();\nvoid print( char * );\nvoid println()"
},
{
"path": "src/simple_kernel.asm",
"chars": 274,
"preview": "start:\n\tmov ax, cs\n\tmov ds, ax\n\t\n\t; --- ;\n\t\n\tmov si, hello_string\n\tcall print_string\n\t\n\tjmp $\n\nprint_string:\n\tmov ah, 0E"
},
{
"path": "src/starter.asm",
"chars": 2528,
"preview": "bits 16\nextern kernel_main\nextern interrupt_handler\nextern scheduler\nextern run_next_process\nextern page_directory\n\nglob"
},
{
"path": "src/str.c",
"chars": 330,
"preview": "#include \"str.h\"\n\nvoid strcpy( char *dest, char *src )\n{\n\tint idx = 0;\n\t\n\twhile ( *src != '\\0' )\n\t{\n\t\tdest[ idx ] = *src"
},
{
"path": "src/str.h",
"chars": 61,
"preview": "void strcpy( char *, char * );\nint strcmp( char *, char * );\n"
}
]
About this extraction
This page contains the full source code of the MaaSTaaR/539kernel GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 93 files (103.0 KB), approximately 40.9k tokens, and a symbol index with 126 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.