about summary refs log tree commit diff stats
path: root/apps/bos/4.asm
blob: 71c51d970ee4d5623cd7ccc2c7bcb1aec3e543b8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
; A boot sector that enters 32-bit protected mode.
;
; To convert to a disk image:
;   cd apps/bos
;   nasm 4.asm -f bin -o boot.bin
; To run:
;   qemu-system-i386 boot.bin
; Or:
;   bochs  # bochsrc loads boot.bin

[org 0x7c00]

  mov bp, 0x9000
  mov sp, bp

  mov bx, MSG_REAL_MODE
  call print_string

  call switch_to_pm
  ; never gets here

  jmp $

switch_to_pm:
  cli
  lgdt [gdt_descriptor]
  ; set LSB of CR0
  mov eax, cr0
  or eax, 0x1
  mov cr0, eax
  jmp CODE_SEG:init_pm  ; Far jump to a new segment containing 32-bit code.
                        ; This also forces the CPU to flush its cache of
                        ; prefetched and real-mode decoded instructions.
  ; never gets here

;; === GDT stuff
gdt_start:

gdt_null:  ; the mandatory null descriptor
  dd 0x0  ; ’dd’ means define double word (i.e. 4 bytes)
  dd 0x0

gdt_code: ; the code segment descriptor
  ; base=0x0, limit=0xfffff,
  ; 1st flags: (present)1 (privilege)00 (descriptor type)1 -> 1001b
  ; type flags: (code)1 (conforming)0 (readable)1 (accessed )0 -> 1010b
  ; 2nd flags: (granularity)1 (32-bit default)1 (64-bit seg)0 (AVL)0 -> 1100b
  dw 0xffff     ; Limit (bits 0-15)
  dw 0x0        ; Base (bits 0-15)
  db 0x0        ; Base (bits 16 -23)
  db 10011010b  ; 1st flags, type flags
  db 11001111b  ; 2nd flags, Limit (bits 16-19)
  db 0x0        ; Base (bits 24 -31)

gdt_data: ; the  data segment descriptor
  ; Same as code segment except for the type flags:
  ; type flags: (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010b
  dw 0xffff    ; Limit (bits 0-15)
  dw 0x0       ; Base (bits 0-15)
  db 0x0       ; Base (bits 16 -23)
  db 10010010b ; 1st flags, type flags
  db 11001111b ; 2nd flags, Limit (bits 16-19)
  db 0x0       ; Base (bits 24 -31)

gdt_end:

gdt_descriptor:
  dw gdt_end - gdt_start - 1  ; last valid byte
  dd gdt_start

; some handy constants
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
;; === end GDT stuff

;; some 16-bit helpers

; print string whose address is in bx
print_string:
  pusha
  mov ah, 0x0e
loop:
  mov al, [bx]
  int 0x10
  add bx, 1
  cmp al, 0
  jne loop
  popa
  ret

;; 32-bit code starts here
[bits  32]

; Initialise registers and the stack once in PM.
init_pm:

  mov ax, DATA_SEG        ; Now in PM, our old segments are meaningless,
  mov ds, ax              ; so we point our segment registers to the
  mov ss, ax              ; data selector we defined in our GDT
  mov es, ax
  mov fs, ax
  mov gs, ax

  mov ebp, 0x90000        ; Update our stack position so it is right
  mov esp, ebp            ; at the top of the free space.

  ;; Protected Mode is now initialized

  mov ebx, MSG_PROT_MODE
  call print_string_pm

  ; all done; hang
  jmp $

; Define  some  constants
VIDEO_MEMORY  equ 0xb8000
WHITE_ON_BLACK  equ 0x0f

; prints a null -terminated  string  pointed  to by EDX
print_string_pm:
  pusha
  mov edx, VIDEO_MEMORY  ; Set  edx to the  start  of vid  mem.
print_string_pm_loop:
  mov al, [ebx]          ; Store  the  char at EBX in AL
  mov ah, WHITE_ON_BLACK ; Store  the  attributes  in AH
  cmp al, 0         ; if (al == 0), at end of string , so
  je print_string_pm_done
  mov [edx], ax     ; Store  char  and  attributes  at  current
                    ; character  cell.
  add ebx , 1       ; Increment  EBX to the  next  char in  string.
  add edx , 2       ; Move to next  character  cell in vid  mem.
  jmp  print_string_pm_loop   ; loop  around  to  print  the  next  char.
print_string_pm_done:
  popa
  ret               ; Return  from  the  function

; Global variables
MSG_REAL_MODE   db "Started in 16-bit Real Mode", 0
MSG_PROT_MODE   db "Successfully landed in 32-bit Protected Mode", 0

; Bootsector padding
times 510-($-$$) db 0
dw 0xaa55