In the lines from 14 to 19 I set up the GDT and start the protected mode.In the line number 21 I make a far jump that should make the program print the caracters from 'A' to 'F'.In the line 44 I put the size of the GDT. Each entry has a size of 8 bytes and I only have 2 entries: The null descriptor (because everybody recommends to put it) and the descriptor that I want to test. Total: 16 bytes (0x10)In the line 45 I put the start location of the GDT: 0x7C00 (where the bootloader is loaded) + 0x0083 = 0x7C83In the line 47 I set the null descriptorIn the line 49 I set the maximum size possible for a segment, as also did in line 52 with the four onesIn the line 50 I put the location where I would like to set the code segment: the location of the print_c 'A' instruction.In the line 51 I set the access byte with the following values:- bit 0: This bit tells us whether the segment is accessed by CPU, so it should be set to zero- bit 1: Make the code segment read-only instead of unreadable- bit 2: Not conforming. This way we don't need any privileges- bit 3: Is a code segment, so it should be executable.- bit 4: Reserved, always 1- bit 5 and 6: 11 (3 in binary) because is the lowest privilege level.This way the segment is more accessible. Anyway, bit 2 make this bit useless.- bit 7: Wheter the segment is present or not. I don't get it, but I set it to 1 because I think it should be 1 to be usable.The first 4 bits in the line 52 are the size again, so I set it to 1111 because I want it to be the greatest possible so I don't have problems with the size (I'm just testing the GDT)The last 4 bits in the line 52 I set the entry flag bits this way:- bit 0 and 1: Reserved, always zero- bit 2: size --> zero (16 bit mode)- bit 3: granularity --> I don't want this, so zero.And finally the line 53 with the last byte of the address of the segment.

However, this doesn't do anything. What I am missing?

_________________Sorry if I commit some mistakes writting english. It is not my native language. If you find a typo in my posts, send me a PM

You need an IDT before you can enable interrupts in protected mode. Segment selector 0x0001 is the null segment. Other than a handful of exceptions, you can't use the BIOS in protected mode. Every group of bytes you've written is backwards (x86 is little endian). Every group of bits you've written is backwards (x86 is insane but not that insane).

I suggest not wasting your time with 16-bit segments in protected mode. They're completely obsolete and useless on any CPU newer than the 286. I also suggest not wasting your time with nonzero segments in real mode and nonzero segment base addresses in protected mode.

mikegonta wrote:

A simple way to access the real mode BIOS while in protected mode.

That doesn't exist, so there's no point in wasting time trying to find it. (Anyone who claims otherwise doesn't understand it well enough.)

I am not using interrupts so I don't need an IDT because I am writting to the screen though video memory (0x8B000).In the line number 32 I make a far jump to 0x8:next to set the cs register with the second descriptor (Each descriptor's size is 8 bytes and the second is the code descriptor, so I think I should use 0x8).In the line 16 I load 'es' with the value 0x10 because the data descriptor is the second descriptor and 0x8*2 = 0x10This time I use db with commas instead of dw, dd or dq because I don't want to have problems with little endian.These are now the values of the descriptors:#0 & #A: Limit with the maximum possible value. This is a test program that is only supposed to print something in screen. I don't want problems with the size.#1, #2 & #F: Base at the start of the memory.#3: If the segment has been accessed or not. Therefore, zero#4: Read/Write. I don't want to have problems so I set this to 1#5: Direction/Conforming. Zero means no privilege level needed to use.#6: Executable. This is only in the first case.#7: Reserved, always 1#8: Kernel privilege.#9: Present. I want to use it. Therefore 1.#B & #C: Reserved, always zero.#D: Size. As Octocontrabass suggest I use 32 bit.#E: Granularity. I think I don't need it.I am spending a lot of time trying to find a way to get this working and I really would appreciate a minimal example that only have GDT and print something using it. This tutorial http://wiki.osdev.org/GDT_Tutorial use C code, but I want to do this in NASM.

_________________Sorry if I commit some mistakes writting english. It is not my native language. If you find a typo in my posts, send me a PM

Last edited by 4dr14n31t0r on Wed Nov 15, 2017 2:08 am, edited 1 time in total.

To sum up the errors: x86 is little Endian. Some of your structures and data have bytes in reverse order. You shouldn't have to hard code addresses like 0x7c32 into data structures. You can use labels for that. In your GDT you have the bytes in the correct order but the access byte and flags have all the bits in reverse order. You are also missing a bits 32 directive after the JMP so you end up with incorrect instruction encoding. Should look like:

Code:

jmp 0x8:next

bits 32next:

You should be setting ES, DS, SS descriptors to 0x0010 and the base in the descriptor should be 0x00000000 not 0x000b8000 (I know what you are trying to do but it is very inefficient that way). The normal way makes a 4gb flat model and most x86 CPUs are optimized for the case where the base is 0x00000000. If you want to write to video memory just move with something like mov [b8000], 0x####. You can modify your write_c macro to compute the address and the attr/character at assembly time.

In the code above the macro has something an LCP (Length Changing Prefix) stall because it uses an imm16 value in a move to a memory operand. It is cheaper (performance wise) to do the mov of an imm32 value into a 32-bit register and then move the lower 16-bit register into memory. The change would look like:

On an unrelated note, you should consider making sure the A20 line is enabled. If you run it on hardware or a virtual machine where this isn't the case then memory addresses starting on an odd numbered megabyte boundary will not work as expected.

Last edited by MichaelPetch on Thu Nov 16, 2017 4:23 pm, edited 1 time in total.

Ok, I get it. But I still don't get something:This wiki(http://wiki.osdev.org/Global_Descriptor_Table) says that bit 0 of access byte is the accessed bit and bit 7 is the present bit. 0 is smaller than 7, so it goes before. But you say that the bits are in reverse order. WTF?Here is the image:And I have a theory that I would like to confirm: In the following image the bits from 0 to 16 are the limit. Is that also in little endian? For example, if I want the limit to be 0xFFF0 (65520 in decimal), and the start of the descriptor is, let say, at 0x0800 (for example), How would the memory at that location be filled?a) 0x0800 --> 0xFF; 0x0801 --> 0xF0b) 0x0800 --> 0xF0; 0x0801 --> 0xFFThe image clearly shows that the limit is the bits from 0 to 15 in memory, but doesn't specify if those 2 bytes should be in little endian or not. I know that the x86 works with little endian, but I don't know how computer internally accesses that memory. I think that this could sound kinda stupid, but if I access the limit byte by byte then the limit would be in big endian. I think so because I see a separate byte of limit in bits 48-51 and I don't know if the computer first take the word from bits 0-15 and the byte from 48-51 and then do some operations to get the Limit bytes in the correct order or just obtain the entire limit byte by byte to easily obtain it in the correct order. I think I am overthinking this simple concept.

Something similar happens to me with the jmp instruction: I know that I shouldn't be hardcoding the location of the jmp instruction, but when I do something like:

Code:

jmp ABCD

I have to see how NASM internally assembles that instruction because I don't know if NASM think that ABCD is the location where I want to jump without little endian conversion and should make that conversion for me, or if I already considered the little endian and only have to put that number in the output binary file as is.

_________________Sorry if I commit some mistakes writting english. It is not my native language. If you find a typo in my posts, send me a PM

I think that you perhaps need to brush up on your understanding of the processor and assembler coding before proceeding further.

Try assembling some simple programs, and run them under a debugger such as gdb. Examine the memory locations and registers, and see how they relate to the instructions and change as the instructions are executed.

Without a thorough understanding of the underlying hardware, and how it works in practice, you are just going to flounder with the more complicated stuff.

This wiki(http://wiki.osdev.org/Global_Descriptor_Table) says that bit 0 of access byte is the accessed bit and bit 7 is the present bit. 0 is smaller than 7, so it goes before. But you say that the bits are in reverse order. WTF?

There's bit order, and then there's byte order.

Bits are always written in the same order. The most-significant bit is on the left and the least-significant bit is on the right. This matches how numbers are written in base 10, so to keep things simple we write numbers the same way in every other base system too.

Bits are not always numbered the same way. Intel has decided that the least-significant bit is bit 0, and any bits of greater significance are numbered from there. So, for example, a constant with only bit 7 set would be written 0b10000000 or 0x80, and a constant with only bit 15 set would be written 0b10000000_00000000 or 0x8000.

Bytes are not always written in the same order. Intel says the least-significant byte goes at the lowest memory address, which means in your code you have to put the byte containing bit 0 first. Your assembler will do this automatically when you write a value that takes more than one byte; for example, "dw 0x1234" is equivalent to "db 0x34,0x12".

Unless otherwise specified, you should assume for everything x86 that bit 0 is the least-significant bit and the least-significant byte is at the lowest address.

Who is online

You cannot post new topics in this forumYou cannot reply to topics in this forumYou cannot edit your posts in this forumYou cannot delete your posts in this forumYou cannot post attachments in this forum