Consolidate most constant memory addresses in bootasm.h part1/2. Convert
[dragonfly.git] / sys / boot / i386 / pxeldr / pxeldr.S
1 /*
2  * Copyright (c) 2000 John Baldwin
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are freely
6  * permitted provided that the above copyright notice and this
7  * paragraph and the following disclaimer are duplicated in all
8  * such forms.
9  *
10  * This software is provided "AS IS" and without any express or
11  * implied warranties, including, without limitation, the implied
12  * warranties of merchantability and fitness for a particular
13  * purpose.
14  *
15  *
16  * $FreeBSD: src/sys/boot/i386/pxeldr/pxeldr.s,v 1.9 2003/09/03 08:12:20 phk Exp $
17  * $DragonFly: src/sys/boot/i386/pxeldr/Attic/pxeldr.S,v 1.4 2004/07/18 23:40:09 dillon Exp $
18  */
19
20 /*
21  * This simple program is a preloader for the normal boot3 loader.  It is
22  * simply prepended to the beginning of a fully built and btxld'd loader.
23  * It then copies the loader to the address boot2 normally loads it,
24  * emulates the boot[12] environment (protected mode, a bootinfo struct,
25  * etc.), and then jumps to the start of btxldr to start the boot process.
26  * This method allows a stock /boot/loader to be booted over the network
27  * via PXE w/o having to write a separate PXE-aware client just to load
28  * the loader.
29  */
30 #include "../bootasm.h"
31
32                 /*
33                  * a.out header fields
34                  */
35                 .set AOUT_TEXT,0x04             # text segment size
36                 .set AOUT_DATA,0x08             # data segment size
37                 .set AOUT_BSS,0x0c              # zerod BSS size
38                 .set AOUT_SYMBOLS,0x10          # symbol table
39                 .set AOUT_ENTRY,0x14            # entry point
40                 .set AOUT_HEADER,MEM_PAGE_SIZE  # size of the a.out header
41
42                 /*
43                  * Flags for kargs->bootflags
44                  */
45                 .set KARGS_FLAGS_PXE,0x2        # flag to indicate booting from
46                                                 #  PXE loader
47                 /*
48                  * Boot howto bits
49                  */
50                 .set RB_SERIAL,0x1000           # serial console
51
52                 /*
53                  * Segment selectors.
54                  */
55                 .set SEL_SDATA,0x8              # Supervisor data
56                 .set SEL_RDATA,0x10             # Real mode data
57                 .set SEL_SCODE,0x18             # PM-32 code
58                 .set SEL_SCODE16,0x20           # PM-16 code
59
60                 /*
61                  * BTX constants
62                  */
63                 .set INT_SYS,0x30               # BTX syscall interrupt
64
65                 /*
66                  * Bit in BDA_KEYBOARD that is set if an enhanced
67                  * keyboard is present.
68                  */
69                 .set KEYBOARD_BIT,0x10
70
71                 /*
72                  * We expect to be loaded by the BIOS at LOAD (0x7c00),
73                  * which is the standard boot loader entry point.
74                  */
75                 .code16
76                 .globl start
77                 .org 0x0, 0x0
78
79                 /*
80                  * BTX program loader for PXE network booting
81                  */
82 start:          cld                             # string ops inc
83                 xorw %ax, %ax                   # zero %ax
84                 movw %ax, %ss                   # setup the
85                 movw $start, %sp                #  stack
86                 movw %es, %cx                   # save PXENV+ segment
87                 movw %ax, %ds                   # setup the
88                 movw %ax, %es                   #  data segments
89                 andl $0xffff, %ecx              # clear upper words
90                 andl $0xffff, %ebx              #  of %ebx and %ecx
91                 shll $4, %ecx                   # calculate the offset of
92                 addl %ebx, %ecx                 #  the PXENV+ struct and
93                 pushl %ecx                      #  save it on the stack
94                 movw $welcome_msg, %si          # %ds:(%si) -> welcome message
95                 callw putstr                    # display the welcome message
96
97                 /*
98                  * Setup the arguments that the loader is expecting
99                  * from boot[12]
100                  */
101                 movw $bootinfo_msg, %si         # %ds:(%si) -> boot args message
102                 callw putstr                    # display the message
103                 movw $MEM_ARG, %bx              # %ds:(%bx) -> boot args
104                 movw %bx, %di                   # %es:(%di) -> boot args
105                 xorl %eax, %eax                 # zero %eax
106                 movw $(MEM_ARG_SIZE/4), %cx     # Size of arguments in 32-bit
107                                                 #  dwords
108                 rep                             # Clear the arguments
109                 stosl                           #  to zero
110                 orb $KARGS_FLAGS_PXE, 0x8(%bx)  # kargs->bootflags |=
111                                                 #  KARGS_FLAGS_PXE
112                 popl 0xc(%bx)                   # kargs->pxeinfo = *PXENV+
113 #ifdef ALWAYS_SERIAL
114                 /*
115                  * set the RBX_SERIAL bit in the howto byte.
116                  */
117                 orl $RB_SERIAL, (%bx)           # enable serial console
118 #endif
119 #ifdef PROBE_KEYBOARD
120                 /*
121                  * Look at the BIOS data area to see if we have an enhanced
122                  * keyboard.  If not, set the RBX_SERIAL bit in the howto 
123                  * byte.
124                  */
125                 testb $KEYBOARD_BIT, BDA_KEYBOARD # keyboard present?
126                 jnz keyb                        # yes, so skip
127                 orl $RB_SERIAL, (%bx)           # enable serial console
128 keyb:
129 #endif
130                 /*
131                  * Turn on the A20 address line
132                  */
133                 callw seta20                    # Turn A20 on
134
135                 /*
136                  * Relocate the loader and BTX using a very lazy protected
137                  * mode
138                  */
139                 movw $relocate_msg, %si         # Display the
140                 callw putstr                    #  relocation message
141                 movl end+AOUT_ENTRY, %edi       # %edi is the destination
142                 movl $(end+AOUT_HEADER), %esi   # %esi is
143                                                 #  the start of the text
144                                                 #  segment
145                 movl end+AOUT_TEXT, %ecx        # %ecx = length of the text
146                                                 #  segment
147                 lgdt gdtdesc                    # setup our own gdt
148                 cli                             # turn off interrupts
149                 movl %cr0, %eax                 # Turn on
150                 orb $0x1, %al                   #  protected
151                 movl %eax, %cr0                 #  mode
152                 ljmp $SEL_SCODE,$pm_start       # long jump to clear the
153                                                 #  instruction pre-fetch queue
154                 .code32
155 pm_start:       movw $SEL_SDATA, %ax            # Initialize
156                 movw %ax, %ds                   #  %ds and
157                 movw %ax, %es                   #  %es to a flat selector
158                 rep                             # Relocate the
159                 movsb                           #  text segment
160                 addl $(MEM_PAGE_SIZE - 1), %edi # pad %edi out to a new page
161                 andl $~(MEM_PAGE_SIZE - 1), %edi #  for the data segment
162                 movl end+AOUT_DATA, %ecx        # size of the data segment
163                 rep                             # Relocate the
164                 movsb                           #  data segment
165                 movl end+AOUT_BSS, %ecx         # size of the bss
166                 xorl %eax, %eax                 # zero %eax
167                 addb $3, %cl                    # round %ecx up to
168                 shrl $2, %ecx                   #  a multiple of 4
169                 rep                             # zero the
170                 stosl                           #  bss
171                 movl end+AOUT_ENTRY, %esi       # %esi -> relocated loader
172                 addl $MEM_BTX_LDR_OFF, %esi     # %esi -> BTX in the loader
173                 movl $MEM_BTX_ORG, %edi # %edi -> where BTX needs to go
174                 movzwl 0xa(%esi), %ecx          # %ecx -> length of BTX
175                 rep                             # Relocate
176                 movsb                           #  BTX
177                 ljmp $SEL_SCODE16,$pm_16        # Jump to 16-bit PM
178                 .code16
179 pm_16:          movw $SEL_RDATA, %ax            # Initialize
180                 movw %ax, %ds                   #  %ds and
181                 movw %ax, %es                   #  %es to a real mode selector
182                 movl %cr0, %eax                 # Turn off
183                 andb $~0x1, %al                 #  protected
184                 movl %eax, %cr0                 #  mode
185                 ljmp $0,$pm_end                 # Long jump to clear the
186                                                 #  instruction pre-fetch queue
187 pm_end:         sti                             # Turn interrupts back on now
188
189                 /*
190                  * Copy the BTX client to MEM_BTX_USR
191                  */
192                 xorw %ax, %ax                   # zero %ax and set
193                 movw %ax, %ds                   #  %ds and %es
194                 movw %ax, %es                   #  to segment 0
195                 movw $MEM_BTX_USR, %di          # Prepare to relocate
196                 movw $btx_client, %si           #  the simple btx client
197                 movw $(btx_client_end-btx_client), %cx # length of btx client
198                 rep                             # Relocate the
199                 movsb                           #  simple BTX client
200
201                 /*
202                  * Copy the boot[12] args to where the BTX client can
203                  * see them
204                  */
205                 movw $MEM_ARG, %si              # where the args are at now
206                 movw $MEM_BTX_USR_ARG, %di              # where the args are moving to
207                 movw $(MEM_ARG_SIZE/4), %cx     # size of the arguments in longs
208                 rep                             # Relocate
209                 movsl                           #  the words
210
211                 /*
212                  * Save the entry point so the client can get to it later on
213                  */
214                 movl end+AOUT_ENTRY, %eax       # load the entry point
215                 stosl                           # add it to the end of the
216                                                 #  arguments
217                 /*
218                  * Now we just start up BTX and let it do the rest
219                  */
220                 movw $jump_message, %si         # Display the
221                 callw putstr                    #  jump message
222                 ljmp $0,$MEM_BTX_ENTRY          # Jump to the BTX entry point
223
224                 /*
225                  * Display a null-terminated string
226                  */
227 putstr:         lodsb                           # load %al from %ds:(%si)
228                 testb %al,%al                   # stop at null
229                 jnz putc                        # if the char != null, output it
230                 retw                            # return when null is hit
231 putc:           movw $0x7,%bx                   # attribute for output
232                 movb $0xe,%ah                   # BIOS: put_char
233                 int $0x10                       # call BIOS, print char in %al
234                 jmp putstr                      # keep looping
235
236                 /*
237                  * Enable A20
238                  */
239 seta20:         cli                             # Disable interrupts
240 seta20.1:       inb $0x64,%al                   # Get status
241                 testb $0x2,%al                  # Busy?
242                 jnz seta20.1                    # Yes
243                 movb $0xd1,%al                  # Command: Write
244                 outb %al,$0x64                  #  output port
245 seta20.2:       inb $0x64,%al                   # Get status
246                 testb $0x2,%al                  # Busy?
247                 jnz seta20.2                    # Yes
248                 movb $0xdf,%al                  # Enable
249                 outb %al,$0x60                  #  A20
250                 sti                             # Enable interrupts
251                 retw                            # To caller
252
253                 /*
254                  * BTX client to start btxldr
255                  */
256                 .code32
257 btx_client:     movl $(MEM_BTX_USR_ARG-MEM_BTX_USR+MEM_ARG_SIZE-4), %esi
258                                                 # %ds:(%esi) -> end
259                                                 #  of boot[12] args
260                 movl $(MEM_ARG_SIZE/4), %ecx    # Number of words to push
261                 std                             # Go backwards
262 push_arg:       lodsl                           # Read argument
263                 pushl %eax                      # Push it onto the stack
264                 loop push_arg                   # Push all of the arguments
265                 cld                             # In case anyone depends on this
266                 pushl MEM_BTX_USR_ARG-MEM_BTX_USR+MEM_ARG_SIZE # Entry point of
267                                                 #  the loader
268                 pushl %eax                      # Emulate a near call
269                 movl $0x1, %eax                 # "exec" system call
270                 int $INT_SYS                    # BTX system call
271 btx_client_end:
272                 .code16
273
274                 .p2align 4
275
276                 /*
277                  * Global descriptor table.
278                  */
279 gdt:            .word 0x0,0x0,0x0,0x0           # Null entry
280                 .word 0xffff,0x0,0x9200,0xcf    # SEL_SDATA
281                 .word 0xffff,0x0,0x9200,0x0     # SEL_RDATA
282                 .word 0xffff,0x0,0x9a00,0xcf    # SEL_SCODE (32-bit)
283                 .word 0xffff,0x0,0x9a00,0x8f    # SEL_SCODE16 (16-bit)
284 gdt.1:
285
286                 /*
287                  * Pseudo-descriptors.
288                  */
289 gdtdesc:        .word gdt.1-gdt-1               # Limit
290                 .long gdt                       # Base
291
292 welcome_msg:    .asciz  "PXE Loader 1.00\r\n\n"
293 bootinfo_msg:   .asciz  "Building the boot loader arguments\r\n"
294 relocate_msg:   .asciz  "Relocating the loader and the BTX\r\n"
295 jump_message:   .asciz  "Starting the BTX loader\r\n"
296
297                 .p2align 4
298 end: