A
A
Arseniy Khusainov2022-03-23 23:42:40
assembler
Arseniy Khusainov, 2022-03-23 23:42:40

How to increase memory for kernel variables and functions in C?

When reaching or more than a certain number of variables or functions, all string literals in the C core stop working, how can I increase the memory for them?

mbr.asm loader:

[org 0x7c00]
KERNEL_OFFSET equ 0x1000 ; The same one we used when linking the kernel

mov [BOOT_DRIVE], dl ; Remember that the BIOS sets us the boot drive in 'dl' on boot
mov bp, 0x8000 ; 0x8000
mov sp, bp

mov bx, MSG_16BIT_MODE
call print16
call print16_nl

call load_kernel ; read the kernel from disk
call switch_to_32bit ; disable interrupts, load GDT,  etc. Finally jumps to 'BEGIN_PM'
jmp $ ; Never executed

%include "boot/print-16bit.asm"
%include "boot/print-32bit.asm"
%include "boot/disk.asm"
%include "boot/gdt.asm"
%include "boot/switch-to-32bit.asm"

[bits 16]
load_kernel:
    mov bx, MSG_LOAD_KERNEL
    call print16
    call print16_nl

    mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
    mov dh, 54 ;31 or 54
    mov dl, [BOOT_DRIVE]
    call disk_load
    ret

[bits 32]
BEGIN_32BIT:
    mov ebx, MSG_32BIT_MODE
    call print32
    call KERNEL_OFFSET ; Give control to the kernel
    jmp $ ; Stay here when the kernel returns control to us (if ever)


BOOT_DRIVE db 0 ; It is a good idea to store it in memory because 'dl' may get overwritten
MSG_16BIT_MODE db "Started in 16-bit Real Mode", 0
MSG_32BIT_MODE db "Landed in 32-bit Protected Mode", 0
MSG_LOAD_KERNEL db "Loading kernel into memory", 0

; padding
times 510 - ($-$$) db 0
dw 0xaa55


Boot from disk.asm:

; load 'dh' sectors from drive 'dl' into ES:BX
disk_load:
    pusha
    ; reading from disk requires setting specific values in all registers
    ; so we will overwrite our input parameters from 'dx'. Let's save it
    ; to the stack for later use.
    push dx

    mov ah, 0x02 ; ah <- int 0x13 function. 0x02 = 'read'
    mov al, dh   ; al <- number of sectors to read (0x01 .. 0x80)
    mov cl, 0x02 ; cl <- sector (0x01 .. 0x11)
                 ; 0x01 is our boot sector, 0x02 is the first 'available' sector
    mov ch, 0x00 ; ch <- cylinder (0x0 .. 0x3FF, upper 2 bits in 'cl')
    ; dl <- drive number. Our caller sets it as a parameter and gets it from BIOS
    ; (0 = floppy, 1 = floppy2, 0x80 = hdd, 0x81 = hdd2)
    mov dh, 0x00 ; dh <- head number (0x0 .. 0xF)

    ; [es:bx] <- pointer to buffer where the data will be stored
    ; caller sets it up for us, and it is actually the standard location for int 13h
    int 0x13      ; BIOS interrupt
    jc disk_error ; if error (stored in the carry bit)

    pop dx
    cmp al, dh    ; BIOS also sets 'al' to the # of sectors read. Compare it.
    jne sectors_error
    popa
    ret


disk_error:
    mov bx, DISK_ERROR
    call print16
    call print16_nl
    mov dh, ah ; ah = error code, dl = disk drive that dropped the error
    call print16_hex ; check out the code at http://stanislavs.org/helppc/int_13-1.html
    jmp disk_loop

sectors_error:
    mov bx, SECTORS_ERROR
    call print16

disk_loop:
    jmp $

DISK_ERROR: db "Disk read error", 0
SECTORS_ERROR: db "Incorrect number of sectors read", 0


gdt.asm:

gdt_start: ; don't remove the labels, they're needed to compute sizes and jumps
    ; the GDT starts with a null 8-byte
    dd 0x0 ; 4 byte
    dd 0x0 ; 4 byte

; GDT for code segment. base = 0x00000000, length = 0xfffff
; for flags, refer to os-dev.pdf document, page 36
gdt_code:
    dw 0xffff    ; segment length, bits 0-15
    dw 0x0       ; segment base, bits 0-15
    db 0x0       ; segment base, bits 16-23
    db 10011010b ; flags (8 bits)
    db 11001111b ; flags (4 bits) + segment length, bits 16-19
    db 0x0       ; segment base, bits 24-31

; GDT for data segment. base and length identical to code segment
; some flags changed, again, refer to os-dev.pdf
gdt_data:
    dw 0xffff
    dw 0x0
    db 0x0
    db 10010010b
    db 11001111b
    db 0x0

gdt_end:

; GDT descriptor
gdt_descriptor:
    dw gdt_end - gdt_start - 1 ; size (16 bit), always one less of its true size
    dd gdt_start ; address (32 bit)

; define some constants for later use
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start


code loader in C - kernel-entry.asm:

global _start
[bits 32]

_start:
    [extern _start_kernel] ; Define calling point. Must have same name as kernel.c 'main' function
    call _start_kernel ; Calls the C function. The linker will know where it is placed in memory
    jmp $


GNU Linker linker.ld:

ENTRY(_start)

SECTIONS
{
  . = 0x1000;
  .text : { *(.text) }
  .data : { *(.data) }
  .bss  : { *(.bss) *(COMMON) }
}


compilation on Windows compile.bat:

gcc -ffreestanding -m32 -g -c kernel/kernel.c -o kernel/kernel.o -std=c11
gcc -ffreestanding -m32 -g -c kernel/util.c -o kernel/util.o -std=c11
gcc -ffreestanding -m32 -g -c kernel/mem.c -o kernel/mem.o -std=c11
gcc -ffreestanding -m32 -g -c kernel/system.c -o kernel/system.o -std=c11

gcc -ffreestanding -m32 -g -c drivers/ports.c -o drivers/ports.o -std=c11
gcc -ffreestanding -m32 -g -c drivers/display.c -o drivers/display.o -std=c11
gcc -ffreestanding -m32 -g -c drivers/keyboard.c -o drivers/keyboard.o -std=c11

gcc -ffreestanding -m32 -g -c cpu/idt.c -o cpu/idt.o -std=c11
gcc -ffreestanding -m32 -g -c cpu/isr.c -o cpu/isr.o -std=c11
gcc -ffreestanding -m32 -g -c cpu/timer.c -o cpu/timer.o -std=c11

nasm -fbin boot/mbr.asm -o boot/mbr.bin
nasm -felf boot/kernel-entry.asm -o boot/kernel-entry.o
nasm -felf cpu/interrupt.asm -o cpu/interrupt.o

ld -mi386pe -no-PIE -o kernel.out -Tlinker.ld boot/kernel-entry.o kernel/kernel.o  kernel/util.o kernel/mem.o drivers/ports.o drivers/display.o drivers/keyboard.o cpu/idt.o cpu/interrupt.o cpu/isr.o cpu/timer.o kernel/system.o
objcopy -I elf32-i386 kernel.out kernel.elf
objcopy -O binary kernel.elf kernel.bin
type boot\\mbr.bin kernel.bin > os-image.bin
qemu-system-i386 -fda os-image.bin


readelf -a kernel.elf in two cases: https://pastebin.com/kTgGc2Yd

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2022-03-24
@halwarsing

When reaching or exceeding a certain number of variables or functions, all string literals in the C core stop working

Certain - what is it?
Right here
mov bx, KERNEL_OFFSET ; Read from disk and store in 0x1000
    mov dh, 54 ;31 or 54

You load 54 sectors of the kernel into memory. Is there any correlation?
How can I increase the memory for them?

you did not bring the kernel code, what breaks there, you can only guess, well, you understand.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question