Fix reversed interrupt vector name
[viridis.git] / asm / realmode.asm-bin
1 /*
2    
3  This is a weird environment. The secondary threads are tossed here in 16 bit
4  real mode from a SIPI. Similar to Linux, this file is compiled separately, and
5  then INCBIN'd into an ELF file as a binary.
6
7  There a couple of reasons it makes sense to ditch ELF for this.
8
9  - This code won't be able to address anything in the kernel thanks to 16 bit
10  segmentation, so we gain nothing in this code from linking it into the kernel
11  proper. Meanwhile, everything this code needs has to be within reach of the
12  segmented memory, so it makes sense for this to be entirely standalone.
13
14  - The SIPI forces this code to be in the first 1M of memory, and page aligned.
15  This is hard to accomplish with the linker when your entire kernel starts at
16  1M, without adding a bunch of padding or confusing our already complex linker
17  script. We get around this by copying the contents of this file to an
18  appropriate location before we SIPI. Because of this copy, any linker
19  relocation even within this file would be useless.
20
21  Now while binary compilation solves these issues, the cost is that we need the
22  boot CPU to communicate any addresses we're going to need at runtime and so,
23  again similar to Linux, we setup a struct in memory the boot CPU can fill in
24  for us.
25
26  */
27
28 #include <memmap.h>
29 #include <apic.h>
30
31 #include <asm/gdt.h>
32 #include <asm/idt.h>
33 #include <asm/realmode.h>
34
35 /* Assumptions */
36
37 #define CODESEL_32  0x8
38 #define DATASEL_32  0x10
39
40 .code16
41 .global _start
42 _start:
43     jmp main /* Skip our header data */
44
45 crthree:
46     .long 0
47 gdtr:
48     .quad 0
49 kernel_entry:
50     .quad 0
51
52 main:
53     lgdtl %cs:(builtin_gdtr - REALMODE_PA)
54
55     mov %cr0, %eax
56     or $1, %eax
57     mov %eax, %cr0
58
59     ljmpw $(0x8), $(host_local_gdt)
60
61 .code32
62
63 host_local_gdt:
64     mov $(DATASEL_32), %ax
65     mov %ax, %ss
66     mov %ax, %ds
67     mov %ax, %es
68     mov %ax, %fs
69     mov %ax, %gs
70
71     lidt rm_idtr
72
73     /* While we're in 32 bit pmode, grab our APIC ID */
74
75     /* NOTE: The APIC is still in xapic mode, so the lower 8 bits
76      * of the ID are in the high 8 bits of the register, but if I 
77      * understand the docs, the full 32 bit value is indeed in place.
78      * Needs testing with > 256 IDs.
79      */
80
81     mov $(MSR_IA32_APIC_BASE), %ecx
82     rdmsr
83
84     and $(BASE_ADDR_MASK), %eax
85     add $(MMIO_OFFSET(APIC_ID)), %eax
86
87     mov (%eax), %edi
88     rol $8, %edi
89
90     /* This init is taken from head.asm */
91
92     /* PAE */
93     mov %cr4, %eax
94     or  $(1 << 5), %eax
95     mov %eax, %cr4
96
97     /* CR3 */
98     mov (crthree), %eax
99     mov %eax, %cr3
100
101     /* Long Mode */
102     mov $(0xc0000080), %ecx
103     rdmsr
104     or  $(1 << 8), %eax
105     wrmsr
106
107     /* paging */
108     mov %cr0, %eax
109     or  $(1 << 31), %eax
110     mov %eax, %cr0
111
112     ljmp $(0x18), $(go_64)
113 go_64:
114
115 .code64
116
117     mov (gdtr), %rax
118     lgdt (%rax)
119
120     jmp kernel_gdt
121
122 kernel_gdt:
123     /* We now share a GDT with the rest of the kernel */
124
125     mov $(DATASEL_32), %ax
126     mov %ax, %ss
127     mov %ax, %ds
128     mov %ax, %es
129     mov %ax, %fs
130     mov %ax, %gs
131
132     mov $(KERNEL_STACK_VIRTUAL), %rcx
133
134     mov %rdi, %rax
135     mov $(STACK_V_SIZE), %rdx
136     mul %rdx
137
138     or %rax, %rcx
139     add $(STACK_SIZE - 8), %rcx
140     mov %rcx, %rsp
141
142     jmpq *(kernel_entry)
143
144 .align 8
145 builtin_gdtr:
146 .word (builtin_gdt_end - builtin_gdt) - 1
147 .quad builtin_gdt
148
149 builtin_gdt:
150 GDTENTRY    0, 0x0, 0x0
151 GDTENTRY    FLAGS_CODE_32, 0, 0xFFFFF
152 GDTENTRY    FLAGS_DATA_32, 0, 0xFFFFF
153 GDTENTRY    FLAGS_CODE_64, 0, 0xFFFFF
154 builtin_gdt_end:
155
156 .align 0x400
157 .rept 21
158 jmp .
159 .endr
160
161 #define RM_ISR_SIZE     2
162
163 .align 8
164 RM_IDT:
165 .set a, (REALMODE_PA + 0x400)
166 .rept 21
167 IDTENTRY(a)
168 .set a, (a+RM_ISR_SIZE)
169 .endr
170 RM_IDTEND:
171
172 .align 8
173 rm_idtr:
174 .word (RM_IDTEND - RM_IDT - 1)
175 .quad RM_IDT