Skip to content

Commit

Permalink
Introduce master kernel page directory. Kernel memory allocation pgd …
Browse files Browse the repository at this point in the history
…entry is

stored in master PGD instead per CPU PGD. CPUs will fault in and populate their
corresponding local PGD entries from master PGD entries in page fault handler.
Placed master and per CPU pgd aligned to 4 MB after kernel text and data.
Corrected identity mapping clear code as well as TLB flushing.
Maps all of the kernel text and data from boot32.
Previously, kernel text and data should be fit in 4MB but now it supports bigger kernel image.
  • Loading branch information
shoily committed May 25, 2022
1 parent de6097f commit 7595ae9
Show file tree
Hide file tree
Showing 19 changed files with 246 additions and 221 deletions.
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<b>XIS</b> operating system needs only 2MB of memory to run.<br>
<b>XIS</b> operating system.<br>

It supports boot loader, kernel with protected mode, paging, E820 enumeration, interrupt and exception handling, system calls, user mode, local APIC, ACPI and multiprocessor.

Expand Down Expand Up @@ -34,8 +34,6 @@ ld -static -T kernel32.ld -m elf_i386 -nostdlib --nmagic boot32.o util.o system.

objdump -x xiskernel.elf | grep _end_kernel_initial_pg_table | awk -Wposix '{cmd="printf %d 0x" $1; cmd | getline decimal; close(cmd); if (decimal > 4294963200) print "STOP: Not enough memory to map pagetables. Upgrade to 64bit kernel.";}'<br>
objcopy -O binary xiskernel.elf xiskernel.bin<br>
echo ".equ KERNEL_SIZE, &#96;ls -l xiskernel.bin | cut -f5 -d\ &#96;" > krnlsize.S<br>
awk '/KERNEL_SIZE/{var=$3; cmd="objdump -x xiskernel.elf | grep INITIAL_KMAPPED_MEMORY | cut -f1 -d\\ "; cmd | getline hex;close(cmd); cmd="printf %d 0x" hex; cmd | getline decimal; if ((var-4096) > decimal) printf("STOP: Map atleast 0x%x bytes in boot32.S. Currently mapped 0x%x bytes", var, decimal);}' krnlsize.S<br>

<b>Instructions for building boot loader -</b><br>
cat krnlconst.hdr | awk '{ if(substr($1, 0, 1) != "#") {print ".equ " $1 ", " $2}; }' > krnlconst.S<br>
Expand Down
4 changes: 2 additions & 2 deletions acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ void acpi_init() {
}

rsdt = (ACPI_TABLE*)ADDPTRS(rsdp->rsdt_address, KERNEL_VIRT_ADDR);
map_kernel_linear_with_pagetable((addr_t)rsdt, sizeof(ACPI_TABLE), PTE_PRESENT, MAP_LOCAL_CPU);
map_kernel_linear_with_pagetable((addr_t)rsdt, rsdt->length, PTE_PRESENT, MAP_LOCAL_CPU);
map_kernel_linear_with_pagetable((addr_t)rsdt, sizeof(ACPI_TABLE), PTE_PRESENT, 0);
map_kernel_linear_with_pagetable((addr_t)rsdt, rsdt->length, PTE_PRESENT, 0);
printf(KERNEL_INFO, "RSDT: %p ", (long)rsdt-KERNEL_VIRT_ADDR);
printf(KERNEL_INFO, "RSDT Length: %d, %d ", rsdt->length, sizeof(ACPI_TABLE));

Expand Down
9 changes: 3 additions & 6 deletions apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ void read_msr(int msr, int *eax, int *edx) {
__asm__ __volatile__("rdmsr;"
: "=a" (*eax), "=d" (*edx)
: "c" (msr)
: );
: "memory");
}

int lapic_read_register(int lapic_register) {
Expand Down Expand Up @@ -74,7 +74,7 @@ void init_lapic() {
"movl %%edx, %0;"
: "=r" (local_lapic_present)
:
: "%eax", "%edx"
: "%eax", "%edx", "memory"
);

printf(KERNEL_INFO, "Local APIC present: %d ", local_lapic_present);
Expand All @@ -83,13 +83,10 @@ void init_lapic() {
return;
}

// memset(lapic_pg_table, 0, sizeof(lapic_pg_table));
// pgtable[0] = (pte_t*)lapic_pg_table;

read_msr(0x1b, &eax, &edx);
lapic_base_register = eax & 0xfffff000;

map_kernel_with_pagetable(lapic_base_register, lapic_base_register, PAGE_SIZE, PTE_WRITE, MAP_LOCAL_CPU);
map_kernel_with_pagetable(lapic_base_register, lapic_base_register, PAGE_SIZE, PTE_WRITE, 0);

lapic_present = local_lapic_present;

Expand Down
100 changes: 88 additions & 12 deletions boot32.S
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,81 @@
.include "krnlconst.S"

.globl _start
.globl _end_kernel_init_text
_start:

// initializing kernel page directory with zero
movl $_kernel_pg_dir, %edi
// initializing master kernel page directory with zero
cld
movl $_master_kernel_pg_dir-KERNEL_VIRT_ADDR, %edi
movl $1024, %ecx
movl $0, %eax
1:
stosl
loop 1b

// populating page directory entries for identity mapping and at 0x80000000
// aligns end of pgds with PGD_SIZE (currently 4MB)
movl $_kernel_pg_table_0-KERNEL_VIRT_ADDR, %eax
addl $~PGD_MASK, %eax
andl $PGD_MASK, %eax

// page tables pages in bytes
shrl $(PGD_SHIFT-PAGE_SHIFT), %eax

// end of page tables
addl $_kernel_pg_table_0-KERNEL_VIRT_ADDR, %eax
movl %eax, %ebx

// aligns end of page tables with PGD_SIZE (currently 4MB)
addl $~PGD_MASK, %eax
andl $PGD_MASK, %eax

testl %eax, %ebx
jnz 1f

// we fit all mapping of kernel code, page directories
// and page tables using our calculated end of page tables.
// But we will not be able to map more page tables because we
// have exhausted all the entries in the last page table about to be
// mapped. So the solution is to add one more page table. Now, we can extend
// more page tables because the first entry of the new page table maps itself.
addl $PAGE_SIZE, %ebx
movl %ebx, %eax
addl $~PGD_MASK, %eax
andl $PGD_MASK, %eax
1:
// eax stores end of page table aligned with PGD_SIZE to
// populate page directory entries.
// ebx stores end of page table
movl %ebx, _end_kernel_mapped_memory-KERNEL_VIRT_ADDR

// populating page directory entries for both identity mapping and at 0x80000000
movl %eax, %ecx
shrl $PGD_SHIFT, %ecx
movl $_kernel_pg_table_0-KERNEL_VIRT_ADDR, %edx
leal 0x1(%edx), %eax
movl %eax, _kernel_pg_dir-KERNEL_VIRT_ADDR
movl %eax, _kernel_pg_dir-KERNEL_VIRT_ADDR+KERNEL_PGDIR_OFFSET
movl $_master_kernel_pg_dir-KERNEL_VIRT_ADDR, %edi
movl $_master_kernel_pg_dir-KERNEL_VIRT_ADDR+KERNEL_PGDIR_OFFSET, %edx
1:
movl %eax, (%edx)
movl %eax, (%edi)
addl $4, %edx
addl $4, %edi
addl $PAGE_SIZE, %eax
loop 1b

// populating page table entries that maps 4MB spaces starting from memory address 0
// both page directory and page table entry should be located in first 4 GB.
// populating page table entries
cld
movl $0x3, %eax
movl $1024, %ecx
movl %ebx, %ecx
shrl $PAGE_SHIFT, %ecx
movl $_kernel_pg_table_0-KERNEL_VIRT_ADDR, %edi

1:
stosl
addl $0x1000, %eax
loop 1b

// turning on paging
movl $_kernel_pg_dir-KERNEL_VIRT_ADDR, %eax
movl $_master_kernel_pg_dir-KERNEL_VIRT_ADDR, %eax
movl %eax, %cr3
movl %cr0, %eax
orl $0x80000000, %eax
Expand All @@ -58,19 +103,50 @@ _start:

highaddress:

// invalidate TLB for identity mapping
movl %ebx, %ecx
shrl $PAGE_SHIFT, %ecx
movl %eax, 0
1:
invlpg (%eax)
addl $PAGE_SIZE, %eax
loop 1b

// invalidate identity mapping
movl $0, _kernel_pg_dir
invlpg (0)
movl %ebx, %ecx
addl $~PGD_MASK, %ecx
andl $PGD_MASK, %ecx
shrl $PGD_SHIFT, %ecx

movl %ecx, %eax
movl $0, %eax
movl $_master_kernel_pg_dir, %edi
cld
1:
stosl
loop 1b

// setting up kernel mode stack in high address
movl $(_kernel_stack_0_start), %esp
movl %esp, %ebp

call start_kernel

movl $9, %eax
addl $48, %eax
orl $(0xF << 8), %eax
movl %eax, VIDEO_BUFFER+KERNEL_VIRT_ADDR

loop:
jmp loop

_end_kernel_init_text:

.data
.global _end_kernel_mapped_memory
.align 8
_end_kernel_mapped_memory:
.long 0
// load smp binary code here
.section mp_init, "ax"
.global init_ap
Expand Down
11 changes: 4 additions & 7 deletions bootldr.S
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ e820_next_entry:

e820_failed:

// write 'E' in the screen to indicate e820 error
// write 'E' on the screen to indicate e820 error
movb $'E', %al
movb $0x0e, %ah
int $0x10
Expand All @@ -93,7 +93,7 @@ e820_done:
// store e820 count in memory
movl %ebp, E820_MAP_COUNT

// write '8' in the screen to indicate e820 success
// write '8' on the screen to indicate e820 success
movb $'8', %al
movb $0x0e, %ah
int $0x10
Expand Down Expand Up @@ -153,9 +153,6 @@ a20_line:

jc lba_read_error




// initialize protected mode
cli
xor %ax, %ax
Expand Down Expand Up @@ -184,14 +181,14 @@ a20_line:

lba_read_error:

// write 'X' in the screen to indicate read error
// write 'X' on the screen to indicate read error
movb $'X', %al
movb $0x0e, %ah
int $0x10
jmp loop

kernel_too_big:
// write 'B' in the screen to indicate kernel too big
// write 'B' on the screen to indicate kernel too big
movb $'B', %al
movb $0x0e, %ah
int $0x10
Expand Down
1 change: 1 addition & 0 deletions handlr32.S
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
pop %ds

popa
addl $4, %esp
sti

iret
Expand Down
13 changes: 7 additions & 6 deletions kernel32.ld
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ SECTIONS
.um_init : {*(.um_init); }
. = ALIGN(8);
.mp_init : {*(.mp_init); }
. = ALIGN(4096);
_kernel_pg_dir = .;
_kernel_pg_dir_end = _kernel_pg_dir + (0x1000 * 32);
_kernel_stack_0 = _kernel_pg_dir_end + 0x1000;
. = ALIGN(0x1000);
_kernel_stack_0 = .;
_kernel_stack_0_start = _kernel_stack_0 + 0x2000;
_kernel_stack_end = _kernel_stack_0_start + (0x2000 * 32);
_kernel_pg_table_0 = _kernel_stack_end;
. = ALIGN(0x400000);
_master_kernel_pg_dir = .;
_kernel_pg_dir = _master_kernel_pg_dir + 0x1000;
_kernel_pg_dir_end = _kernel_pg_dir + (0x1000 * 32);
_kernel_pg_table_0 = _kernel_pg_dir_end;
_kernel_pg_table_0_end = _kernel_pg_table_0 + 0x1000;
_end_kernel_initial_pg_table = _kernel_pg_table_0_end;
}
3 changes: 2 additions & 1 deletion krnlconst.hdr
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ KERNEL_PGDIR_OFFSET (KERNEL_VIRT_ADDR>>20)
KERNEL_STACK_SIZE 0x2000
PAGE_SHIFT 12
PAGE_SIZE (1<<PAGE_SHIFT)
PAGE_MASK ~(PAGE_SIZE-1)
PGD_SHIFT 22
PGD_SIZE (1<<PGD_SHIFT)
INITIAL_KMAPPED_MEMORY PGD_SIZE
PGD_MASK ~(PGD_SIZE-1)
2 changes: 1 addition & 1 deletion lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ void spinlock_unlock(spinlock *lock) {
__asm__ __volatile__("movl $0, %0;"
: "=m" (lock->val)
:
: "cc", "memory" );
: "memory" );
}

32 changes: 11 additions & 21 deletions memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@
// CONVERT_64
extern addr_t _kernel_section_start;
extern addr_t _end_kernel_initial_pg_table;
extern addr_t _master_kernel_pg_dir, _kernel_pg_dir;
extern addr_t _kernel_pg_table_0;
extern addr_t init_ap_size;
extern int _end_kernel_mapped_memory;

#define MEM_CACHE_FLAG_ADDING_SLOT 1

Expand Down Expand Up @@ -92,7 +94,6 @@ s32 mem_init() {
addr64_t base_aligned, addr;
// CONVERT_64
addr64_t kpages_memory;
addr_t kpage_beyond_mapping;
addr_t end_kernel_pgtbls;
addr_t mp_addr;
u64 i, j;
Expand All @@ -109,39 +110,26 @@ s32 mem_init() {
if (total_effective_memory > MAX_SUPPORTED_MEMORY)
total_effective_memory = MAX_SUPPORTED_MEMORY;

if (total_effective_memory < INITIAL_KMAPPED_MEMORY)
nr_pgtbls = 0;
else
nr_pgtbls = (ALIGN_PGD(total_effective_memory) >> PGD_SHIFT) - (INITIAL_KMAPPED_MEMORY >> PGD_SHIFT);
nr_pgtbls = (ALIGN_PGD(total_effective_memory) - _end_kernel_mapped_memory) >> PGD_SHIFT;

nr_kpages = (total_effective_memory >> PAGE_SHIFT);
kpages_memory = ALIGN_PAGE(nr_kpages * sizeof(struct kpage));

end_kernel_pgtbls = ADDPTRS(&_end_kernel_initial_pg_table, nr_pgtbls << PAGE_SHIFT);
_end_kernel_mapped_memory += KERNEL_VIRT_ADDR;
end_kernel_pgtbls = ADDPTRS(_end_kernel_mapped_memory, nr_pgtbls << PAGE_SHIFT);
kpage = kpages = (struct kpage *)end_kernel_pgtbls;

if (ADDPTRS(&_end_kernel_initial_pg_table, PAGE_SIZE) >= ADDPTRS(KERNEL_VIRT_ADDR, INITIAL_KMAPPED_MEMORY)) {
sprintf(debug_str, "pgtable for kpages cannot be mapped due to kernel size reaches %d of initial mapping. Increase initial mapping.\n", INITIAL_KMAPPED_MEMORY);
print_vga(debug_str);
return -1;
} else if (ADDPTRS64(PTR64(kpages), kpages_memory) > MAX_SUPPORTED_MEMORY) {
if (ADDPTRS64(PTR64(kpages), kpages_memory) > MAX_SUPPORTED_MEMORY) {
print_vga("Could not map page tables and kpages. Reached maximum limit for 32 bit OS. Upgrade to 64bit kernel\n");
sprintf(debug_str, "_end_kernel_initial_pg_table: %x, nr_pgtbls size: %x, kpages_memory: %x\n", PTR(&_end_kernel_initial_pg_table), PTR(nr_pgtbls << PAGE_SHIFT), PTR(kpages_memory));
sprintf(debug_str, "_end_kernel_mapped_memory: %x, nr_pgtbls size: %x, kpages_memory: %x\n", PTR(_end_kernel_mapped_memory), PTR(nr_pgtbls << PAGE_SHIFT), PTR(kpages_memory));
print_vga(debug_str);
return -1;
}

if (nr_pgtbls)
map_kernel_linear_with_pagetable(ADDPTRS(KERNEL_VIRT_ADDR, INITIAL_KMAPPED_MEMORY), nr_pgtbls << PAGE_SHIFT, PTE_PRESENT | PTE_WRITE, false);
map_kernel_linear_with_pagetable(_end_kernel_mapped_memory, nr_pgtbls << PAGE_SHIFT, PTE_PRESENT | PTE_WRITE, false);

if (ADDPTRS(end_kernel_pgtbls, kpages_memory) > ADDPTRS(KERNEL_VIRT_ADDR, INITIAL_KMAPPED_MEMORY)) {
if ((addr_t)kpages < (addr_t)ADDPTRS(KERNEL_VIRT_ADDR, INITIAL_KMAPPED_MEMORY))
kpage_beyond_mapping = ADDPTRS(KERNEL_VIRT_ADDR, INITIAL_KMAPPED_MEMORY);
else
kpage_beyond_mapping = (addr_t)kpages;

map_kernel_linear_with_pagetable(kpage_beyond_mapping, kpages_memory, PTE_PRESENT | PTE_WRITE, false);
}
map_kernel_linear_with_pagetable(PTR(kpages), kpages_memory, PTE_PRESENT | PTE_WRITE, false);

end_kernel_data = ADDPTRS(kpages, kpages_memory);
kpage_last = kpages;
Expand Down Expand Up @@ -214,6 +202,8 @@ s32 mem_init() {
kpage++;
}

memset(&_kernel_pg_dir, 0, PAGE_SIZE);

return 0;
}

Expand Down
Loading

0 comments on commit 7595ae9

Please sign in to comment.