summaryrefslogtreecommitdiff
path: root/410kern/boot/head.S
blob: d0ecdf29f8212dcd486d0bb454c403256d68fe71 (plain)
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
/**
 * @file boot/head.S
 * @author matthewj
 * @author de0u
 */

/* N.B. This is NOT to be construed as style guidance!! */
/* N.B. This is NOT to be construed as style guidance!! */
/* N.B. This is NOT to be construed as style guidance!! */

#include <simics.h>
#include <x86/video_defines.h>
#include <x86/seg.h>

/** @brief Entry point from the bootloader */
.global _start
/** @brief Start of the kernel image */
.global __kimg_start
/** @brief Start of the init GDT */
.global init_gdt
/** @brief Start of the init IDT */
.global init_idt
/** @brief Start of the init TSS */
.global init_tss
.global init_tss_size

.text

__kimg_start:

mb_header:
    /* Not a complete Multiboot header, but GRUB can live with it. */
    .long 0x1BADB002      /**< Multiboot magic word */
    .long 0x00000000      /**< Flags field */
    .long (0 - 0x1BADB002 - 0x00000000)   /**< Checksum */
    .space 244

init_idt: /* 0x100100 */
    .space 64
    .long 0x001009b8
    .long 0x00108e00
    .space 1976
init_gdt: /* 0x100900 */
    .long 0x00000000
    .long 0x00000000
    /* Next two lines need to be kept in sync with smp/smp.c */
    .long 0x09500067
    .long 0x00008910
    .long 0x0000ffff
    .long 0x00cf9b00
    .long 0x0000ffff
    .long 0x00cf9300
    .long 0x0000ffff
    .long 0x00cffb00
    .long 0x0000ffff
    .long 0x00cff200
    /* Spare segment descriptors follow, see x86/seg.h */
    .long 0x00000000 /**< SEGSEL_SPARE0 word 0 */
    .long 0x00000000
    .long 0x00000000 /**< SEGSEL_SPARE1 word 0 */
    .long 0x00000000
    .long 0x00000000 /**< SEGSEL_SPARE2 word 0 */
    .long 0x00000000
    .long 0x00000000 /**< SEGSEL_SPARE3 word 0 */
    .long 0x00000000
init_tss: /* 0x100950 */
    .space 8
    .word 0x0018
    .space 92 /* fills with 0's */
    .word 0x0068
init_tss_end:

df_handler: /* 0x1009b8 */
    cli
    /* Get something "out there" first thing */
    leal fmsg, %ecx
    movl $SIM_PUTS, %ebx
    xchg %ebx, %ebx
    /* We got here because we were in trouble, so be conservative */
    movl $SEGSEL_KERNEL_DS, %eax
    movw %ax, %ds
    movw %ax, %es
    movw %ax, %fs
    movw %ax, %gs
    movw %ax, %ss
    leal istack, %esp
    subl $2048, %esp      /* try to avoid wiping state */
    /* Now we probably have a runtime environment */
    leal fbytes, %eax
    pushl %eax
    call blat
df_handler_loop:
    jmp df_handler_loop

_start:
    cmpl $0x15410DE0, %eax
    je _guest_start
    cli                   /* I sure HOPE this is superfluous */
    leal istack, %esp     /* Load initial stack pointer */

    movl $init_tss, %eax
    subl $init_gdt, %eax
    subl $1, %eax
    pushl %eax            /* gdt limit == sizeof(gdt)-1 */
    pushl $init_gdt
    call lgdt
    addl $8, %esp

    movl $init_gdt, %eax
    subl $init_idt, %eax
    subl $1, %eax
    pushl %eax            /* idt limit == sizeof(idt)-1 */
    pushl $init_idt
    call lidt
    addl $8, %esp

    movl $SEGSEL_TSS, %eax
    ltr %ax

    pushl %esp            /* Pass in the top of the initial stack */
    pushl %ebx            /* Pass in the multiboot structure */
    call mb_entry         /* Call the C entry point */

    /* "should not get here" */
    pushl $pbytes
    call blat
stuck:
    jmp stuck

_guest_start:
    leal istack, %esp     /* Load initial stack pointer */
    pushl %ecx            /* Max legal vaddr */
    pushl %ebx            /* Number of max legal vframe */
    call hv_guest_entry
    addl $8,%esp          /* In case anybody's keeping score */
    jmp stuck

# void blat(uint8_t *bytes)
blat:
    pushl %ebp
    movl %esp, %ebp
    pushl %ebx
    pushl %esi
    pushl %edi

    movl 8(%ebp), %eax                 # bytes
    pushl %eax
    call strlen
    movl %eax, %edx                    # EDX: strlen(bytes)
    add $4, %esp

    movl $CONSOLE_MEM_BASE, %edi       # EDI: dest

    movl $CONSOLE_WIDTH, %ebx
    imull $CONSOLE_HEIGHT, %ebx
    sall $1, %ebx                      # 2*width*height
    addl %edi, %ebx                    # EBX: limit
    subl %edx, %ebx                    # EBX: limit (round down)

    movl %es, %eax
    pushl %eax                         # save ES
    movl %ds, %eax
    movl %eax, %es                     # force ES to match DS

movs:
    movl %edx, %ecx                    # ECX: count
    movl 8(%ebp), %esi                 # ESI: source
    rep movsb                          # ECX bytes from DS:ESI to ES:EDI
    cmpl %edi, %ebx
    jg movs

    popl %eax
    movl %eax, %es                     # restore ES

    popl %edi
    popl %esi
    popl %ebx
    popl %ebp
    ret

init_tss_size:
	.long (init_tss_end - init_tss)

.data


fmsg:
    .asciz "\n***** Double fault!\n"
fbytes:
    .asciz "D\ro\ru\rb\rl\re\r \rf\ra\ru\rl\rt\r!\r \r"

pmsg:
    .asciz "Kernel cannot return()!"
pbytes:
    .asciz "K\re\rr\rn\re\rl\r \rc\ra\rn\rn\ro\rt\r \rr\re\rt\ru\rr\rn\r(\r)\r!\r \r"

/* Initial stack */
.align 4        
.space 4096
istack: