0

I am developing a 32 bit operating system. I have just implemented paging but came across a problem. My GDT was getting overwritten. That problem was fixed in a previous question. To fix it, I had to load my kernel at 0x8000 instead of 0x1000. But when I try to do that, bochs give me this error:

set_diskette_current_cyl(): drive > 1

But when I look at my code, I see that dl is being set to 0 right before int 0x13. Can someone please explain why this happens?

Full code on GitHub

Full bochs log:

00014693525i[BIOS  ] Booting from 0000:7c00
00015876408i[FLOPPY] partial read() on floppy image returns 7/512
00015920854i[FLOPPY] read() on floppy image returns 0
00015965299i[FLOPPY] read() on floppy image returns 0
00016009745i[FLOPPY] read() on floppy image returns 0
00016054189i[FLOPPY] read() on floppy image returns 0
00016098634i[FLOPPY] read() on floppy image returns 0
00016166924p[BIOS  ] >>PANIC<< set_diskette_current_cyl(): drive > 1
00016166924i[CPU0  ] CPU is in real mode (active)
00016166924i[CPU0  ] CS.mode = 16 bit
00016166924i[CPU0  ] SS.mode = 16 bit
00016166924i[CPU0  ] EFER   = 0x00000000
00016166924i[CPU0  ] | EAX=0000040a  EBX=0000cd4b  ECX=00090200  EDX=00000402
00016166924i[CPU0  ] | ESP=00008f70  EBP=00008f74  ESI=000e0000  EDI=0000ffac
00016166924i[CPU0  ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf ZF af PF cf
00016166924i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
00016166924i[CPU0  ] |  CS:f000( 0004| 0|  0) 000f0000 0000ffff 0 0
00016166924i[CPU0  ] |  DS:f000( 0005| 0|  0) 000f0000 0000ffff 0 0
00016166924i[CPU0  ] |  SS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016166924i[CPU0  ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016166924i[CPU0  ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016166924i[CPU0  ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00016166924i[CPU0  ] | EIP=0000054b (0000054a)
00016166924i[CPU0  ] | CR0=0x60000010 CR2=0x00000000
00016166924i[CPU0  ] | CR3=0x00000000 CR4=0x00000000
00016166924i[CPU0  ] 0x000000000000054a>> out dx, al : EE
00016166924i[CMOS  ] Last time is 1684823363 (Tue May 23 11:59:23 2023)
00016166924i[      ] restoring default signal behavior
========================================================================
Bochs is exiting with the following message:
[BIOS  ] set_diskette_current_cyl(): drive > 1
========================================================================
00016166924i[SIM   ] quit_sim called with exit code 1
modlegend
  • 11
  • 5
  • When you single-step your code inside Bochs, do you still see DL = 0 right before the `int 0x13`? Bochs has a built-in debugger that's quite good. – Peter Cordes May 23 '23 at 06:46
  • Yes, that's what I meant by "when I look at my code, I see that `dl` is being set to 0 right before `int 0x13`" – modlegend May 23 '23 at 06:54
  • That phrasing sounded like you were looking at the source and seeing a `mov dl, 0` or `xor dx,dx` instruction. But if you're single-stepping the actual machine code, you can be sure that's actually going on, that the machine code didn't get stepped on by something before execution. And you can also be sure it's *that* `int 0x13` that executed, not a different one at a different address. Or some jump to it with a different DL value after executing some "garbage" bytes by accident. If you did actually single-step in the debugger, then that would rule that out. – Peter Cordes May 23 '23 at 06:56
  • I'm sorry for the weird phrasing. Though when it actually runs the BIOS code, dl changes a lot. But I'm pretty sure that the BIOS isn't that reckless. – modlegend May 23 '23 at 06:58
  • As long as DL had the desired value when the `int 0x13` instruction itself executed, that's fine. If you can "step over" the `int 0x13` and it produces that error instead of getting to the end, that would confirm that it's this execution complaining, not some some later execution of `int 0x13` with a different DL value. – Peter Cordes May 23 '23 at 07:01
  • I set a breakpoint to the instruction after `int 0x13`, and let the debugger `cont`inue. It threw the error before the breakpoint, so I'm pretty sure it's that instance of `int 0x13` that produces the error. Also, `int 0x13` is only called once in the entire program. – modlegend May 23 '23 at 07:11
  • 2
    I actually informed you of this problem in your previous question in the comments. You may have missed it. My previous comment was: "Remember that you put the stack at 0x9000. If you didn't move it out of the way somewhere else you'll clobber it pretty fast and that will likely cause BIOS interrupts to fail. Putting the stack at 0x0000:0x7c00 (below the bootloader) rather than 0x9000 should work until you get into protected mode." – Michael Petch May 23 '23 at 07:19
  • 2
    What is happening is you set the load address of the kernel at 0x8000 and your existing stack is at 0x9000. You need to move it out of the way so you don't load your kernel on top of it. I recommend 0x0000:0x7c00 if you put the kernel at 0x8000. The stack will grow down in the free space below the bootloader in that case. It will be a place you aren't loading your kernel. `int 13h` fails with strange errors when you are clobbering the stack memory it is using to read the disk. – Michael Petch May 23 '23 at 07:20
  • Thanks @MichaelPetch. I set `bp` and `sp` to 0 now, and it works! For the most part. Now the previous error is thrown. I just saw the Memory Map x86 page of wiki.osdev.org, so I want to know where to put my page directory and page tables without overwriting the EBDA. – modlegend May 23 '23 at 07:39
  • 1
    *Also, int 0x13 is only called once in the entire program.* - That's if the program executes the way you intended. Bugs in asm can lead to running the wrong bytes as machine code, leading to a jump somewhere like I mentioned. Setting a breakpoint after the `int 0x13` is a good way to confirm that something's going wrong with *this* execution of it. (And Michael Petch's explanation makes total sense.) But setting BP and SP to `0`? Stack at linear address 0xFFFE and lower as it grows does leave more space above 0x8000, but not as much as putting the stack at linear address 0x7C00 – Peter Cordes May 23 '23 at 07:42
  • 1
    One thing to note: setting SP to a value without setting SS is a recipe for problems. SS:SP are combined to generate a physical address. Without setting SS you may be pointing the stack somewhere you didn't intend. It just so happens on BOCHS that SS is set to 0 before loading your bootloader. By luck it works, but on real hardware it may not. I have general bootloader tips here: https://stackoverflow.com/a/32705076/3857942 – Michael Petch May 23 '23 at 07:59
  • Since BOCHS set SS to 0 and you never modified it in real mode and you set SP to 0 your stack is 0x0000:0x0000. The first word you push on the stack will be placed at 0x0000:0xfffe because SP wrapped. If you read 32k of kernel into memory starting at 0x8000 you'll be running into the stack again. Note: you should set SS to 0 in real mode followed right after by setting SP so that your code is more likely to run in environments outside BOCHS. I recommend setting SS:SP to 0x0000:0x7c00 near the start of your bootloader with `xor ax, ax` `mov ss, ax` `mov sp, 0x7c00` – Michael Petch May 23 '23 at 08:02
  • The EBDA is in the memory just below physical address 0xA0000. You can read the amount of memory from 0x00000 to the EBDA by reading the word value from memory address starting at 0x413 and shift that value left 10 bits (multiply by 1k). That gives you the physical address to the start of the EBDA. On many systems the EBDA is 1k in size so conventional memory is 640k-1k=639. 639 shifted left 10 bits is 9FC00. 0x9FC00 to 0xA0000 is the EBDA in that case. Anything less than 0x9FC00 should be safe (assuming the BIOS is not some ancient one where the size of conventional memory is reported wrong) – Michael Petch May 23 '23 at 08:18
  • Note: The word value that starts at physical address 0x00413 near the bottom of memory just above the interrupt table happens to be reported conventional memory in KiB. Reading a value of 639 from there means there is 639KiB of memory from 0x00000 to the start of the EBDA. I am using the value 639 as an example because it is a common size you'd read from memory address 0x00413 – Michael Petch May 23 '23 at 08:24
  • Sorry for the late reply, I wasn't on SO for sometime. @MichaelPetch I don't expect my OS size to increase much, so I'm pretty sure I can load my kernel at 0x500, since that's the start of conventional memory. I might load the page structures at 0xC0000000, making a Higher Half Page Directory instead. There'll be enough space there, atleast for identity mapping 1 MiB. I will also be setting `SS`. @PeterCordes, I'll still be positioning the stack at 0, since 0x7C00 isn't a feasible solution now. Thanks all for your help. Also, from now on, I will be posting osdev related questions on osdev.org. – modlegend May 24 '23 at 08:35

0 Answers0