<- previous index next ->
The Intel 80x86 and beyond have privilege levels.
There are instructions that can only be executed at the highest
privilege level, CPL = 0. This would be reserved for the
operating system in order to prevent the average user from
causing chaos. e.g. The average user could issue a HLT instruction
to halt the machine and thus every process would be dead.
Other CPL=0 only instructions include:
CLTS Clear Task Switching flag in cr0
INVP Invalidate cache
INVLPG Invalidate translation lookaside buffer, TLB
WBINVD Write Back and Invalidate cache
It should be obvious that when running a multiprocessing operating
system, that there are many instructions that only the operating
system should use.
The operating system controls the resources of the computer,
including RAM, I/O and user processes. Some sample protections
are tested by the following sample programs:
A few simple tests to be sure protections are working.
These three programs result in segfault, intentionally.
safe_64.asm store into read only section
; safe_64.asm for testing protections within sections
; Assemble: nasm -f elf64 safe_64.asm
; Link: gcc -o safe_64 safe_64.o
; Run: ./safe_64
; Output:
; it should stop with a system caught error
global main ; the standard gcc entry point
extern printf ; the C function, to be called
section .rodata ; read only data section, constants
a: dq 5 ; long int a=5;
fmt: db "Bad, still running",10,0
section .text ; Code section. not writeable
main: ; the program label for the entry point
push rbp ; set up stack frame
mov rax,0x789abcde
mov [a],rax ; should be error, read only section !!!!!!!!!!
mov rdi,fmt ; address of format string
mov rax,0
call printf
pop rbp
mov rax,0 ; normal, no error, return value
ret ; return
safe1_64.asm store into code section
; safe_64.asm for testing protections within sections
; Assemble: nasm -f elf64 safe1_64.asm
; Link: gcc -o safe1_64 safe1_64.o
; Run: ./safe1_64
; Output:
; it should stop with a system caught error
global main ; the standard gcc entry point
extern printf ; the C function, to be called
section .rodata ; read only data section, constants
a: dq 5 ; long int a=5;
fmt: db "Bad, still running",10,0
section .text ; Code section. not writeable
main: ; the program label for the entry point
push rbp ; set up stack frame
mov rax,0x789abcde
mov [main],rax ; should be error, can not change code .text !!!!!!
mov rdi,fmt ; address of format string
mov rax,0
call printf
pop rbp
mov rax,0 ; normal, no error, return value
ret ; return
safe2_64.asm jump (execute) data
; safe2_64.asm for testing protections within sections
; Assemble: nasm -f elf64 safe2_64.asm
; Link: gcc -o safe2_64 safe2_64.o
; Run: ./safe2_64
; Output:
; it should stop with a system caught error
global main ; the standard gcc entry point
extern printf ; the C function, to be called
section .rodata ; read only data section, constants
a: dq 5 ; long int a=5;
fmt: db "Bad, still running",10,0
section .text ; Code section. not writeable
main: ; the program label for the entry point
push rbp ; set up stack frame
mov rax,0x789abcde
jmp a ; should be error, can not execute data !!!!!!!!
mov rdi,fmt ; address of format string
mov rax,0
call printf
pop rbp
mov rax,0 ; normal, no error, return value
ret ; return
A few simple tests to be sure privileged instructions can not execute.
priv_64.asm hlt instruction to halt computer
; priv_64.asm for testing that average user
; can not execute privileged instructions
; Assemble: nasm -f elf64 priv_64.asm
; Link: gcc -o priv_64 priv_64.o
; Run: ./priv_64
; Output:
; it should stop with a system caught error
global main ; the standard gcc entry point
extern printf ; the C function, to be called
fmt: db "bad! Still running",10,0 ; The printf format, "\n",'0'
section .text ; try to halt the computer
main: ; the program label for the entry point
push rbp ; set up stack frame
hlt ; should be error, only allowed in CPL=0 !!!!!!!
mov rdi,fmt ; address of format string
mov rax,0
call printf
pop rbp
mov rax,0 ; normal, no error, return value
ret ; return
priv1_64.asm other privileged instructions
; priv1_64.asm for testing that average user
; can not execute privileged instructions
; Assemble: nasm -f elf64 priv1_64.asm
; Link: gcc -o priv1_64 priv1_64.o
; Run: ./priv1_64
; Output:
; it should stop with a system caught error
global main ; the standard gcc entry point
extern printf ; the C function, to be called
fmt: db "bad! Still running",10,0 ; The printf format, "\n",'0'
section .text ; try to halt the computer
main: ; the program label for the entry point
push rbp ; set up stack frame
clts ; should be error, only allowed in CPL=0 !!!!!!!
wbinvd ; never gets to these, also error
mov rdi,fmt ; address of format string
mov rax,0
call printf
pop rbp
mov rax,0 ; normal, no error, return value
ret ; return
In order to allow the user some access, controlled access, to
system resources, an interface to the operating system, or kernel,
is provided. You will see in the next lecture that some BIOS
functions are also provided as Linux kernel calls.
To implement list in NASMlist_64.c
Here is some sample code related to first "push"
; test_alist_64.asm generating test data in heap and list
; (some list_64.c included as comments)
extern printf
; static char heap[20000] ; space to store strings, do not reuse or free
; static char *hp = heap; ; pointer to next available heap space
; static long int list[1000]; ; space to store list block (2 index+ pointer)
; static long int lp=1; ; index to next available list space
; static char *q; ; q, a pointer to a character
; static long int i; ; a variable index
section .bss
heap: resb 20000 ; could be gigabytes
list: resq 1000 ; could be millions
q: resq 1 ; may be just in rsi
i: resq 1 ; may be just in rdi
section .data
hp: dq heap ; [hp] is pointer to next free heap
lp: dq 1 ; index of next available list item
test: db "middle",0, "last",0, "front",0 ; just using middle
fmt1: db "%s",10,0 ; "%s\n" for printf
fmtend: db 10,0 ; "\n"
; push_back "middle", push_back "last", push_front "front"
; +-----------------+ +-----------------+ +-----------------+
; L[0]-> | index to next----->| index to next----->| 0 |
; | 0 |<-----index to prev |<-----index to prev |<-L[1]
; | ptr to heap str | | ptr to heap str | | ptr to heap str |
; +-----------------+ +-----------------+ +-----------------+
; The pointers to heap strings are character pointers to terminated strings.
; The "index" values could be pointers rather than indices.
global main
main:
push rbp ; save rbp, no registers need saving
;set up test for the first push into the list
mov rax,1 ; initial list index (*8 for address)
mov qword [list+8*rax],0 ; list[1]=0 no more
mov qword [list+8*(rax+1)],0 ; list[2]=0 no more
mov rbx,[hp] ; string address in heap
mov [list+8*(rax+2)],rbx ; list[3] = string address in heap
; set L[0] = 1 = rax this is first push
; set L[1] = 1 = rax
mov rbx, 0 ; clear rbx, we use bl for byte
mov rsi, test ; similar to a push_front call
mov rax, [hp] ; address of heap in rax
move: mov bl, [rsi] ; picks up a character from test
mov [rax], bl ; put character on heap
inc rsi ; increment from address, user
inc rax ; increment to address, heap
cmp bl, 0
jne move
mov [hp],rax ; next available heap address saved
mov rdi, fmt1
mov rsi, heap
mov rax, 0
call printf
pop rbp
mov rax, 0
ret ; return
Questions?
Help with Project ?
<- previous index next ->