OSDev.org https://forum.osdev.org/ |
|
Linker error https://forum.osdev.org/viewtopic.php?f=1&t=33377 |
Page 1 of 1 |
Author: | deleted8917 [ Sat Dec 15, 2018 3:00 pm ] |
Post subject: | Linker error |
Hello, here bothering again with stupid questions. I've been trying to add an IDT to my OS (real mode). I managed to create the PIC successfully, now I try to add the IDT but when I compile I get this error from the linker: boot.o: In function `irq0': kernel/irq.inc:56: undefined reference to `irq0_handler' boot.o: In function `irq1': kernel/irq.inc:62: undefined reference to `irq1_handler' boot.o: In function `irq2': kernel/irq.inc:68: undefined reference to `irq2_handler' boot.o: In function `irq3': kernel/irq.inc:74: undefined reference to `irq3_handler' boot.o: In function `irq4': kernel/irq.inc:80: undefined reference to `irq4_handler' boot.o: In function `irq5': kernel/irq.inc:86: undefined reference to `irq5_handler' boot.o: In function `irq6': kernel/irq.inc:92: undefined reference to `irq6_handler' boot.o: In function `irq7': kernel/irq.inc:98: undefined reference to `irq7_handler' boot.o: In function `irq8': kernel/irq.inc:104: undefined reference to `irq8_handler' boot.o: In function `irq9': kernel/irq.inc:110: undefined reference to `irq9_handler' boot.o: In function `irq10': kernel/irq.inc:116: undefined reference to `irq10_handler' boot.o: In function `irq11': kernel/irq.inc:122: undefined reference to `irq11_handler' boot.o: In function `irq12': kernel/irq.inc:128: undefined reference to `irq12_handler' boot.o: In function `irq13': kernel/irq.inc:134: undefined reference to `irq13_handler' boot.o: In function `irq14': kernel/irq.inc:140: undefined reference to `irq14_handler' boot.o: In function `irq15': kernel/irq.inc:146: undefined reference to `irq15_handler' kmain.o: In function `kernelmain': /mnt/c/Users/nicol/Desktop/ckernel/kmain.c:26: undefined reference to `idt_init' Here's the entire source of my OS: https://transfer.sh/tjoLh/ckernel.tar.gz I need to make my own interrupts, so I can my OS MS-DOS compatible. I borrowed the PIC and IDT code from OSDev btw |
Author: | Octocontrabass [ Sat Dec 15, 2018 3:34 pm ] |
Post subject: | Re: Linker error |
konniskatt wrote: I've been trying to add an IDT to my OS (real mode). You can't. The IDT is a protected mode structure. In real mode, you must have an IVT instead. As for those linker errors, are you sure you're including all of your code when you link it together? It looks like your build script might be missing some pieces. |
Author: | deleted8917 [ Sat Dec 15, 2018 6:18 pm ] |
Post subject: | Re: Linker error |
Sorry for being stupid and confusing IDT with IVT. So now, how can I make my own interruptions with IVT? OSDev wiki doesn't explain much about IVT |
Author: | alexfru [ Sun Dec 16, 2018 7:01 am ] |
Post subject: | Re: Linker error |
konniskatt wrote: Sorry for being stupid and confusing IDT with IVT. So now, how can I make my own interruptions with IVT? OSDev wiki doesn't explain much about IVT The IVT resides at physical address 0. It has 256 4-byte entries. Each entry is a far address of the ISR (far address being a pair of 16-bit values: offset (at lower address), segment (at higher address)). IRQs (and the int instruction) would cause FLAGS, CS, IP pushed (in that order, that is, FLAGS at higher address, CS in the middle, IP at the lower address) before the corresponding ISR is entered. FLAGS.IF is automatically cleared upon entry thus disabling nested/recursive handling of interrupts. Each ISR should preserve all registers and return with IRET. IRET pops IP, CS, FLAGS from the stack to resume execution of the interrupted code. That's about it. The rest (the PIC and I/O ports) should be agnostic of the CPU mode. However, to program for real mode comfortably (w.r.t. segmentation and that implies interrupts too) you need a compiler that actually supports it (unless you want to write lots of asm code, which is the opposite of comfortable). AFAIK, gcc doesn't quite support it out of the box, I mean the segmentation part specifically. You want something like Open Watcom C/C++ or Smaller C instead. You'll need to learn those and how to load a DOS-style .EXE (or you could use a loader that can do that, e.g. BootProg). It may be a good start to use OW or Smaller C in some sort of DOS, FreeDOS or DOSBox. It'll be easy to set up the IVT and try out your ISRs there. This part will be the same in DOS and your system. |
Author: | MichaelPetch [ Sun Dec 16, 2018 3:33 pm ] |
Post subject: | Re: Linker error |
alexfru wrote: IRQs (and the int instruction) would cause FLAGS, CS, IP pushed (in that order, that is, FLAGS at higher address, CS in the middle, IP at the lower address) before the corresponding ISR is entered. I'd probably also point out that any reference to error codes in the OSDev Wiki being pushed by the processor after the return address doesn't apply in real mode.Of course replacing interrupts in real mode has the downside in that if you don't chain to the old BIOS routines, BIOS function calls may no longer work as expected. In some cases chaining to some interrupts isn't straight forward (especially the keyboard) if you want to get it right. Example: If you intercept the hard disk controller interrupts without calling the old interrupt routines in your handler- the hard disk likely won't work. Replacing the timer interrupt (IRQ0) without calling the old one can cause a host of failures for other BIOS calls (like the floppy drive and hard drive access) that may need a timer. |
Author: | deleted8917 [ Mon Dec 17, 2018 6:52 am ] |
Post subject: | Re: Linker error |
Now I'm rewriting my entire OS, and now is a protected mode OS, but the linker (again) are complaining that sections overlap section .sig loaded at [00000000000007fe,00000000000007ff] overlaps section .boot loaded at [0000000000000600,0000000000000880] Code: OUTPUT_FORMAT("elf32-i386");
ENTRY(boot_start); BOOTLOADER_BASE = 0x7c00; BOOTLOADER_RELOC = 0x600; SECTOR_SIZE = 512; KERNEL_BASE = BOOTLOADER_RELOC + SECTOR_SIZE; SECTIONS { __boot_reloc_addr = BOOTLOADER_RELOC; __boot_base_addr = BOOTLOADER_BASE; __sector_sizew = SECTOR_SIZE>>1; . = BOOTLOADER_RELOC; /* Code and data in boot.o placed between 0x7c00 and 0x7e00 */ .boot : SUBALIGN(0) { boot.o(.text*) boot.o(.rodata*) boot.o(.data) } . = BOOTLOADER_RELOC + 0x200 - 2; /* Boot signature at 510th byte from beginning of bootloader's base */ .sig : { SHORT(0xaa55); } KERNEL_ADJ = KERNEL_BASE - .; . = KERNEL_BASE; __disk_load_start = .; __disk_load_seg = (__disk_load_start) >> 4; /* Kernel code and data */ .kernel : AT(ADDR(.kernel) - KERNEL_ADJ) SUBALIGN(4) { *(.text*) *(.rodata*) *(.data) } __disk_load_end = .; __disk_load_num_sectors = (__disk_load_end - __disk_load_start + (SECTOR_SIZE - 1)) / SECTOR_SIZE; .kernel.bss : SUBALIGN(4) { __bss_start = .; *(COMMON); *(.bss) . = ALIGN(4); __bss_end = .; } __bss_sizew = SIZEOF(.kernel.bss)>>1; /* Remove unnecessary sections */ /DISCARD/ : { *(.eh_frame); *(.comment); } } |
Author: | MichaelPetch [ Mon Dec 17, 2018 7:09 am ] |
Post subject: | Re: Linker error |
This is because you have put too much code into the boot sector which is 512 bytes long and it has begun to overlap the boot signature. The reason appears to be because you have included a bunch of IRQ related routine into the boot sector (boot.asm). You should be removing that irq related INC file from the boot sector, rename it to a .asm file (place a section .text at the top) and build it as a separate assembly object (with nasm) and add that object to your linking command. |
Author: | deleted8917 [ Mon Dec 17, 2018 7:33 am ] |
Post subject: | Re: Linker error |
Follow their suggestions and now compile without problems, but does not jump (boot2.asm) to kernelmain (kmain.c) boot.asm Code: ; These symbols are defined by the linker. We use them to zero BSS section extern __bss_start extern __bss_sizew ; These symbols are length (in sectors) of the kernel, ; and segment in memory to start reading to extern __disk_load_num_sectors extern __disk_load_seg extern __sector_sizew; ; Mmory address to relocate the bootsector from / to extern __boot_base_addr extern __boot_reloc_addr extern proc_mode ; This is the C entry point defined in kmain.c ;extern kernelmain ; kernelmain is C entry point global boot_start ; Make this global to suppress linker warning KERNEL_LBA_START equ 1 ; Logical Block Address(LBA) kernel starts on ; LBA 1 = sector after boot sector KERNEL_LBA_END equ KERNEL_LBA_START + __disk_load_num_sectors ; Logical Block Address(LBA) kernel ends at DISK_RETRIES equ 3 ; Number of times to retry on disk error section .text bits 16 ; Include a BPB (1.44MB floppy with FAT12) %include "bpb.inc" ;%include "boot2.inc" boot_start: ; This code up until label .reloc must be position independent xor eax, eax ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00 mov ds, ax mov es, ax mov ss, ax ; Stack at 0x0000:0x0000 mov esp, eax ; After first push will be 0x0000:0xfffe at top of 64kb ; Copy bootloader from __boot_base_addr (0x7c00) to __boot_reloc_addr (0x600) ; We copy the bootloader to low memory above the BIOS Data Area (BDA) to allow ; more space for the kernel. cld mov cx, __sector_sizew mov si, __boot_base_addr mov di, __boot_reloc_addr rep movsw ; Jump to the relocated boot sector and set CS=0 jmp 0x0000:.reloc .reloc: ; Read kernel 1 sector at a time until kernel loaded load_kernel: mov [bootDevice], dl ; Save boot drive mov di, __disk_load_seg ; DI = Current segment to read into mov si, KERNEL_LBA_START ; SI = LBA that kernel starts at jmp .chk_for_last_lba ; Check to see if we are last sector in kernel .read_sector_loop: mov bp, DISK_RETRIES ; Set disk retry count call lba_to_chs ; Convert current LBA to CHS mov es, di ; Set ES to current segment number to read into xor bx, bx ; Offset zero in segment .retry: mov ax, 0x0201 ; Call function 0x02 of int 13h (read sectors) ; AL = 1 = Sectors to read int 0x13 ; BIOS Disk interrupt call jc .disk_error ; If CF set then disk error .success: add di, 512>>4 ; Advance to next 512 byte segment (0x20*16=512) inc si ; Next LBA .chk_for_last_lba: cmp si, KERNEL_LBA_END ; Have we reached the last kernel sector? jl .read_sector_loop ; If we haven't then read next sector .kernel_loaded: jmp launch_kernel ; Do realmode initialization and run kernel .disk_error: xor ah, ah ; Int13h/AH=0 is drive reset int 0x13 dec bp ; Decrease retry count jge .retry ; If retry count not exceeded then try again error_end: ; Unrecoverable error; print drive error; enter infinite loop mov si, diskErrorMsg ; Display disk error message call print_string cli .error_loop: hlt jmp .error_loop ; Function: print_string ; Display a string to the console on display page 0 ; ; Inputs: SI = Offset of address to print ; Clobbers: AX, BX, SI print_string: mov ah, 0x0e ; BIOS tty Print xor bx, bx ; Set display page to 0 (BL) jmp .getch .repeat: int 0x10 ; print character .getch: lodsb ; Get character from string test al,al ; Have we reached end of string? jnz .repeat ; if not process next character .end: ret ; Function: lba_to_chs ; Description: Translate Logical block address to CHS (Cylinder, Head, Sector). ; Works for all valid FAT12 compatible disk geometries. ; ; Resources: http://www.ctyme.com/intr/rb-0607.htm ; https://en.wikipedia.org/wiki/Logical_block_addressing#CHS_conversion ; https://stackoverflow.com/q/45434899/3857942 ; Sector = (LBA mod SPT) + 1 ; Head = (LBA / SPT) mod HEADS ; Cylinder = (LBA / SPT) / HEADS ; ; Inputs: SI = LBA ; Outputs: DL = Boot Drive Number ; DH = Head ; CH = Cylinder (lower 8 bits of 10-bit cylinder) ; CL = Sector/Cylinder ; Upper 2 bits of 10-bit Cylinders in upper 2 bits of CL ; Sector in lower 6 bits of CL ; ; Notes: Output registers match expectation of Int 13h/AH=2 inputs ; lba_to_chs: push ax ; Preserve AX mov ax, si ; Copy LBA to AX xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV div word [sectorsPerTrack] ; 32-bit by 16-bit DIV : LBA / SPT mov cl, dl ; CL = S = LBA mod SPT inc cl ; CL = S = (LBA mod SPT) + 1 xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV div word [numHeads] ; 32-bit by 16-bit DIV : (LBA / SPT) / HEADS mov dh, dl ; DH = H = (LBA / SPT) mod HEADS mov dl, [bootDevice] ; boot device, not necessary to set but convenient mov ch, al ; CH = C(lower 8 bits) = (LBA / SPT) / HEADS shl ah, 6 ; Store upper 2 bits of 10-bit Cylinder into or cl, ah ; upper 2 bits of Sector (CL) pop ax ; Restore scratch registers ret get_memsz: int 12h mov si, ax call print_string APM_init: ; Checking if APM is supported mov ah, 53h mov al, 00h xor bx, bx int 15h jc APM_error ; Disconnect to any APM interface mov ah, 53h mov al, 04h xor bx, bx int 15h jc .APM_discerr jmp .APM_noerr ; Connect to the real mode interface mov ah, 53h mov al, [01h] xor bx, bx int 15h jc APM_error ; Enable power management mov ah, 53h mov al, 08h mov bx, 0001h mov cx, 0001h int 15h jc APM_error .APM_discerr: cmp ah, 03h jne APM_error .APM_noerr: APM_error: mov si, APMerrorMsg call print_string cli hlt ; Set up segments so they are 0, zero out the BSS memory and transfer ; control to the function kernelmain launch_kernel: mov si, bootloaderMsg call print_string ;jmp APM_init xor ax, ax mov es, ax mov fs, ax mov gs, ax ; ES=FS=GS=0 (we set DS=SS=0 previously) ; We need to zero out the BSS section. We'll do it a WORD at a time mov edi, __bss_start ; Start address of BSS mov ecx, __bss_sizew ; Length of BSS in WORDS ; Clear memory with value in AX (0x0000) rep stosw ; Do clear using string store instruction ; Clear 2 bytes at a time ;call dword kernelmain ; Call kernel's "C" main entry point jmp proc_mode .end_loop: ; Loop forever to terminate when kernel main is finished hlt jmp .end_loop section .data ; Uncomment these lines if not using a BPB (via bpb.inc) ; numHeads: dw 2 ; 1.44MB Floppy has 2 heads & 18 sector per track ; sectorsPerTrack: dw 18 bootDevice: db 0x00 diskErrorMsg: db "panic: Unrecoverable disk error!", 0x0A, 0x0D, 0 bootloaderMsg: db "Starting...", 0x0A, 0x0D, 0 APMerrorMsg: db "panic: APM interface not supported or failed to initialize.", 0x0A, 0x0D, 0 boot2.asm Code: %include "gdt.inc" %include "a20.inc" global proc_mode extern kernelmain proc_mode: cli xor ax, ax mov ds, ax mov es, ax mov ax, 0x9000 mov ss, ax mov sp, 0xFFFF sti ;cli mov eax, cr0 or eax, 1 mov cr0, eax jmp check_a20 ;check_a20 returns 0 to ax if a20 is not activated cmp ax, 0 ; IF ax == 0 THEN je enable_A20 ; jump to enable_A20 jmp InstallGDT ; Starts GDT jmp 08h:proc_mode2 bits 32 ; Tell to NASM that were gonna use 32 bits code (protected mode) proc_mode2: mov ax, 0x10 mov ds, ax mov ss, ax mov es, ax mov esp, 90000h call dword kernelmain a20.inc Code: check_a20: pushf push ds push es push di push si cli xor ax, ax ; ax = 0 mov es, ax not ax ; ax = 0xFFFF mov ds, ax mov di, 0x0500 mov si, 0x0510 mov al, byte [es:di] push ax mov al, byte [ds:si] push ax mov byte [es:di], 0x00 mov byte [ds:si], 0xFF cmp byte [es:di], 0xFF pop ax mov byte [ds:si], al pop ax mov byte [es:di], al mov ax, 0 je check_a20__exit mov ax, 1 check_a20__exit: pop si pop di pop es pop ds popf ret enable_A20: cli call a20wait mov al,0xAD out 0x64,al call a20wait mov al,0xD0 out 0x64,al call a20wait2 in al,0x60 push eax call a20wait mov al,0xD1 out 0x64,al call a20wait pop eax or al,2 out 0x60,al call a20wait mov al,0xAE out 0x64,al call a20wait sti ret a20wait: in al,0x64 test al,2 jnz a20wait ret a20wait2: in al,0x64 test al,1 jz a20wait2 ret gdt.inc Code: InstallGDT: cli ; clear interrupts pusha ; save registers lgdt[toc] ; load GDT into GDTR sti ; enable interrupts popa ; restore registers ret ; All done! ;******************************************* ; Global Descriptor Table (GDT) ;******************************************* gdt_data: dd 0 ; null descriptor dd 0 ; gdt code: ; code descriptor dw 0FFFFh ; limit low dw 0 ; base low db 0 ; base middle db 10011010b ; access db 11001111b ; granularity db 0 ; base high ; gdt data: ; data descriptor dw 0FFFFh ; limit low (Same as code) dw 0 ; base low db 0 ; base middle db 10010010b ; access db 11001111b ; granularity db 0 ; base high end_of_gdt: toc: dw end_of_gdt - gdt_data - 1 ; limit (Size of GDT) dd gdt_data ; base of GDT kmain.c Code: #include <stdint.h>
#define nl "\r\n" // taken from osdev wiki void putch(unsigned char c, unsigned char forecolour, unsigned char backcolour, int x, int y) { uint16_t attrib = (backcolour << 4) | (forecolour & 0x0F); volatile uint16_t * where; where = (volatile uint16_t *)0xB8000 + (y * 80 + x) ; *where = c | (attrib << 8); } void println(char* str) { static int x = 0; static int y = 0; while (*str) { putch(*str++, 7, 0, x, y); ++y; } } int kernelmain() { println("Hello protected mode!"nl); return 0; } |
Author: | MichaelPetch [ Mon Dec 17, 2018 8:23 am ] |
Post subject: | Re: Linker error |
You don't show us the contents of a20.inc and gdt.inc . Hard to say without seeing everything. At this point I highly recommend using BOCHs to step through the code with the built in debugger to see where (and why) things go wrong. There is no reason to set up the stack here: Code: mov ax, 0x9000 . You already set the real mode stack right at the beginning of the boot.asm. You should delete these lines. Secondly SS:SP of 0x9000:0xFFFF may conflict with the EBDA (Extended BIOS Data Area) just below physical address 0xA0000 and that can cause issues, which is yet another reason to remove these. PS:setting SP to 0xFFFF can potentially degrade performance on some processors since it is an odd offset.
mov ss, ax mov sp, 0xFFFF |
Author: | deleted8917 [ Mon Dec 17, 2018 9:16 am ] |
Post subject: | Re: Linker error |
MichaelPetch wrote: You don't show us the contents of a20.inc and gdt.inc . Hard to say without seeing everything. At this point I highly recommend using BOCHs to step through the code with the built in debugger to see where (and why) things go wrong. There is no reason to set up the stack here: Code: mov ax, 0x9000 . You already set the real mode stack right at the beginning of the boot.asm. You should delete these lines. Secondly SS:SP of 0x9000:0xFFFF may conflict with the EBDA (Extended BIOS Data Area) just below physical address 0xA0000 and that can cause issues, which is yet another reason to remove these. PS:setting SP to 0xFFFF can potentially degrade performance on some processors since it is an odd offset.mov ss, ax mov sp, 0xFFFF added gdt.inc, a20.inc, kmain.c btw, the OS is rebooting constantly. |
Author: | MichaelPetch [ Mon Dec 17, 2018 1:35 pm ] |
Post subject: | Re: Linker error |
A lot wrong with this. - When going into protected you need to do it with interrupts off CLI - boot2.asm is missing a bits 16 at the top - boot2.asm you need to set up the GDT before you turn on the protected mode bit in CR0 - boot2.asm preferable to enable a20 before entering protected mode - In gdt.inc and a20.inc it is cleaner to put code and data in their proper sections like .data and .text (not required in this case though) - You incorrectly transfer control to A20 and InstallGDT routines with jmp rather than call - You branch to enable_a20 which is a JMP, not a CALL. You need to CALL enable_a20 if A20 check says A20 is off - You unnecessarily reload the segment registers while in real mode in boot,asm - You set up the real mode stack more than once - You don't do anything like an infinite loop after the kernel returns from the C code - In the kernel you do ++y when advancing to next character and it should be ++x - Your putch routine needs to handle \r and \n characters and alter x and y accordingly. Writing those characters to the screen doesn't advance to the next line of the display automatically. I've put a quick fix in to handle \r and \n but it up to you to handle wrapping at the end of a line to the next, scrolling etc boot.asm: Code: ; These symbols are defined by the linker. We use them to zero BSS section boot2.asm:extern __bss_start extern __bss_sizew ; These symbols are length (in sectors) of the kernel, ; and segment in memory to start reading to extern __disk_load_num_sectors extern __disk_load_seg extern __sector_sizew; ; Mmory address to relocate the bootsector from / to extern __boot_base_addr extern __boot_reloc_addr extern proc_mode ; This is the C entry point defined in kmain.c ;extern kernelmain ; kernelmain is C entry point global boot_start ; Make this global to suppress linker warning KERNEL_LBA_START equ 1 ; Logical Block Address(LBA) kernel starts on ; LBA 1 = sector after boot sector KERNEL_LBA_END equ KERNEL_LBA_START + __disk_load_num_sectors ; Logical Block Address(LBA) kernel ends at DISK_RETRIES equ 3 ; Number of times to retry on disk error section .text bits 16 ; Include a BPB (1.44MB floppy with FAT12) %include "bpb.inc" boot_start: ; This code up until label .reloc must be position independent xor eax, eax ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00 mov ds, ax mov es, ax mov ss, ax ; Stack at 0x0000:0x0000 mov esp, eax ; After first push will be 0x0000:0xfffe at top of 64kb ; Copy bootloader from __boot_base_addr (0x7c00) to __boot_reloc_addr (0x600) ; We copy the bootloader to low memory above the BIOS Data Area (BDA) to allow ; more space for the kernel. cld mov cx, __sector_sizew mov si, __boot_base_addr mov di, __boot_reloc_addr rep movsw ; Jump to the relocated boot sector and set CS=0 jmp 0x0000:.reloc .reloc: ; Read kernel 1 sector at a time until kernel loaded load_kernel: mov [bootDevice], dl ; Save boot drive mov di, __disk_load_seg ; DI = Current segment to read into mov si, KERNEL_LBA_START ; SI = LBA that kernel starts at jmp .chk_for_last_lba ; Check to see if we are last sector in kernel .read_sector_loop: mov bp, DISK_RETRIES ; Set disk retry count call lba_to_chs ; Convert current LBA to CHS mov es, di ; Set ES to current segment number to read into xor bx, bx ; Offset zero in segment .retry: mov ax, 0x0201 ; Call function 0x02 of int 13h (read sectors) ; AL = 1 = Sectors to read int 0x13 ; BIOS Disk interrupt call jc .disk_error ; If CF set then disk error .success: add di, 512>>4 ; Advance to next 512 byte segment (0x20*16=512) inc si ; Next LBA .chk_for_last_lba: cmp si, KERNEL_LBA_END ; Have we reached the last kernel sector? jl .read_sector_loop ; If we haven't then read next sector .kernel_loaded: jmp launch_kernel ; Do realmode initialization and run kernel .disk_error: xor ah, ah ; Int13h/AH=0 is drive reset int 0x13 dec bp ; Decrease retry count jge .retry ; If retry count not exceeded then try again error_end: ; Unrecoverable error; print drive error; enter infinite loop mov si, diskErrorMsg ; Display disk error message call print_string cli .error_loop: hlt jmp .error_loop ; Function: print_string ; Display a string to the console on display page 0 ; ; Inputs: SI = Offset of address to print ; Clobbers: AX, BX, SI print_string: mov ah, 0x0e ; BIOS tty Print xor bx, bx ; Set display page to 0 (BL) jmp .getch .repeat: int 0x10 ; print character .getch: lodsb ; Get character from string test al,al ; Have we reached end of string? jnz .repeat ; if not process next character .end: ret ; Function: lba_to_chs ; Description: Translate Logical block address to CHS (Cylinder, Head, Sector). ; Works for all valid FAT12 compatible disk geometries. ; ; Resources: http://www.ctyme.com/intr/rb-0607.htm ; https://en.wikipedia.org/wiki/Logical_block_addressing#CHS_conversion ; https://stackoverflow.com/q/45434899/3857942 ; Sector = (LBA mod SPT) + 1 ; Head = (LBA / SPT) mod HEADS ; Cylinder = (LBA / SPT) / HEADS ; ; Inputs: SI = LBA ; Outputs: DL = Boot Drive Number ; DH = Head ; CH = Cylinder (lower 8 bits of 10-bit cylinder) ; CL = Sector/Cylinder ; Upper 2 bits of 10-bit Cylinders in upper 2 bits of CL ; Sector in lower 6 bits of CL ; ; Notes: Output registers match expectation of Int 13h/AH=2 inputs ; lba_to_chs: push ax ; Preserve AX mov ax, si ; Copy LBA to AX xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV div word [sectorsPerTrack] ; 32-bit by 16-bit DIV : LBA / SPT mov cl, dl ; CL = S = LBA mod SPT inc cl ; CL = S = (LBA mod SPT) + 1 xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV div word [numHeads] ; 32-bit by 16-bit DIV : (LBA / SPT) / HEADS mov dh, dl ; DH = H = (LBA / SPT) mod HEADS mov dl, [bootDevice] ; boot device, not necessary to set but convenient mov ch, al ; CH = C(lower 8 bits) = (LBA / SPT) / HEADS shl ah, 6 ; Store upper 2 bits of 10-bit Cylinder into or cl, ah ; upper 2 bits of Sector (CL) pop ax ; Restore scratch registers ret get_memsz: int 12h mov si, ax call print_string APM_init: ; Checking if APM is supported mov ah, 53h mov al, 00h xor bx, bx int 15h jc APM_error ; Disconnect to any APM interface mov ah, 53h mov al, 04h xor bx, bx int 15h jc .APM_discerr jmp .APM_noerr ; Connect to the real mode interface mov ah, 53h mov al, [01h] xor bx, bx int 15h jc APM_error ; Enable power management mov ah, 53h mov al, 08h mov bx, 0001h mov cx, 0001h int 15h jc APM_error .APM_discerr: cmp ah, 03h jne APM_error .APM_noerr: APM_error: mov si, APMerrorMsg call print_string cli hlt ; Set up segments so they are 0, zero out the BSS memory and transfer ; control to the function kernelmain launch_kernel: mov si, bootloaderMsg call print_string ;jmp APM_init xor ax, ax mov es, ax ; ES became non-zero during the disk reads ; so we have to set it to zero again ; We need to zero out the BSS section. We'll do it a WORD at a time mov edi, __bss_start ; Start address of BSS mov ecx, __bss_sizew ; Length of BSS in WORDS ; Clear memory with value in AX (0x0000) rep stosw ; Do clear using string store instruction ; Clear 2 bytes at a time jmp proc_mode section .data ; Uncomment these lines if not using a BPB (via bpb.inc) ; numHeads: dw 2 ; 1.44MB Floppy has 2 heads & 18 sector per track ; sectorsPerTrack: dw 18 bootDevice: db 0x00 diskErrorMsg: db "panic: Unrecoverable disk error!", 0x0A, 0x0D, 0 bootloaderMsg: db "Starting...", 0x0A, 0x0D, 0 APMerrorMsg: db "panic: APM interface not supported or failed to initialize.", 0x0A, 0x0D, 0 Code: bits 16 kmain.c:%include "gdt.inc" %include "a20.inc" global proc_mode extern kernelmain section .text proc_mode: call check_a20 ; check_a20 returns 0 to ax if a20 is not activated test ax, ax jnz load_gdt ; If A20 already enable skip to load GDT call enable_A20 ; call enable_A20 to enable A20 since it appears to be off load_gdt: call InstallGDT ; Starts GDT cli mov eax, cr0 or eax, 1 mov cr0, eax jmp 08h:proc_mode2 bits 32 ; Tell to NASM that were gonna use 32 bits code (protected mode) proc_mode2: mov ax, 0x10 mov ds, ax mov fs, ax mov gs, ax mov ss, ax mov es, ax mov ss, ax mov esp, 90000h call kernelmain .end_loop: ; Loop forever to terminate when kernel main is finished hlt jmp .end_loop Code: #include <stdint.h>
#define nl "\r\n" static int x = 0; static int y = 0; // taken from osdev wiki void putch(unsigned char c, unsigned char forecolour, unsigned char backcolour) { uint16_t attrib = (backcolour << 4) | (forecolour & 0x0F); volatile uint16_t * where; if (c == '\r') x = 0; else if (c == '\n') y++; else { where = (volatile uint16_t *)0xB8000 + (y * 80 + x) ; *where = c | (attrib << 8); x++; } } void println(char* str) { while (*str) putch(*str++, 7, 0); } int kernelmain() { println("Hello protected mode!"nl); return 0; } |
Page 1 of 1 | All times are UTC - 6 hours |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |