In a cpu with segmented memory, can an address only be accessed with a segmented address, or can a normal virtual address also be used?
A virtual address is not normal. It is used with paging. "Normal addresses" are direct physical addresses which access main memory directly. Intel's terminology says that virtual address will be translated by the segmentation unit to a linear address. The linear address will then be translated to physical address by the MMU.
With that said the answer to your question is quite complex since it involves understanding operating-system development concepts.
x86 CPUs start with the 8086. Today, the 8086 is emulated at startup of every x86 processor for backward compatibility with older software. This is called real mode. In real mode physical addresses are calculated using the address you specify in the assembly code by implicitly adding ds as the segment selector. They are calculated by the formula
ds * 16 + offset. For example,
mov ax, 0 mov ds, ax mov word [0x1234], 0x1234
will move 0x1234 to the physical address
0x0 * 16 + 0x1234 = 0x1234. With ds set as 0, real mode segmentation is ignored because the address you specify is translated to itself.
After real mode the OS will jump to protected mode. In protected mode there is segmentation and paging available for more recent CPUs. Before paging, there was only segmentation. Paging is more modern than segmentation. For an example on how to set up protected mode in NASM assembly look at the following code:
cli lgdt[gdtr] mov eax, cr0 or al, 1 mov cr0, eax jmp 0x08:protectedMode ;0x08 = 0b1000, 1 for segment selector ;0 for gdt not ldt and 00 for privilege bits 32 protectedMode: gdt_start: dq 0x0 ;null descriptor gdt_code: dw 0xFFFF ;limit 0-15 dw 0x0 ;base 0-15 db 0x0 ;base 16-23 db 10011010b ;pr, privi (2), s, ex, dc, rw, ac db 11001111b ;gr, sz, limit 16-19 db 0x0 ;base 24-31 gdt_data: dw 0xFFFF dw 0x0 db 0x0 db 10010010b db 11001111b db 0x0 gdtr: dw 24 dd gdt_start
The code disables interrupts, loads a GDT, enables protected mode by setting a bit in the CR0 control register then jumps to protected mode in segment 0x08. Segment 0x08 is the code segment. Segment 0 being the null descriptor. Here segmentation is enabled with a flat memory model.
The flat memory model is where you specify a base of 0x0 and a limit of 0xFFFFF with a granularity (gr) of 1. The granularity specify if the limit will be in blocks of 1 byte (0) or 4KB (1). If the limit is in blocks of 4KB and the base is 0 then the segment will span the whole 4GB available address space in protected mode (with a limit of 0xFFFFF). The flat memory model is often used in modern operating systems because it simplifies operations in transition modes before long mode is enabled.
To enable long mode, you must enable paging and set certain bits in some registers. The following code enables long mode in NASM assembly:
mov eax, cr4 ;enable PAE-paging or eax, 1 << 5 mov cr4, eax mov ecx, 0xC0000080 ;set long mode bit in EFER MSR rdmsr or eax, 1 << 8 wrmsr mov eax, cr0 ;enable paging or eax, 1 << 31 mov cr0, eax lgdt[gdtr] ;load a 64 bit gdt (will be ignored afterwards) jmp 0x08:longMode bits 64 longMode: gdt_start: dw 0xFFFF dw 0 db 0 db 0 db 1 db 0 gdt_code: dw 0x1111 ;limit 0-15 dw 0x0 ;base 0-15 db 0x0 ;base 16-23 db 10011010b ;pr, privi (2), s, ex, dc, rw, ac db 10101111b ;gr, sz, limit 16-19 db 0x0 ;base 24-31 gdt_data: dw 0x0000 dw 0x0 db 0x0 db 10010010b db 00000000b db 0x0 gdtr: dw $ - gdt_start - 1 dq gdt_start
The 64 bits GDT is necessary because as stated on osdev.org
Notice that we set a 4gb limit for code. This is needed because the processor will make a last limit check before the jump, and having a limit of 0 will cause a #GP (tested in bochs). After that, the limit will be ignored.
So basically, before we jump in the 64 bits code selector to enter long mode, the processor makes a last limit check. After that, the limit is ignored. This is evident since the limit is only 20 bits and, with a granularity of 4KB, this limits the segments to 4GB. In long mode you have access to much more RAM than that.
Once in long mode, you have paging enabled and everything but the CR3 register is translated by the MMU to a physical address. Everything is a virtual address. Segmentation is ignored.