197873a3dSThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
296ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- *
396ae6ea0SThomas Gleixner *
496ae6ea0SThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds
596ae6ea0SThomas Gleixner * Copyright 2007 rPath, Inc. - All Rights Reserved
67a734e7dSH. Peter Anvin * Copyright 2009 Intel Corporation; author H. Peter Anvin
796ae6ea0SThomas Gleixner *
896ae6ea0SThomas Gleixner * ----------------------------------------------------------------------- */
996ae6ea0SThomas Gleixner
1096ae6ea0SThomas Gleixner /*
1196ae6ea0SThomas Gleixner * Header file for the real-mode kernel code
1296ae6ea0SThomas Gleixner */
1396ae6ea0SThomas Gleixner
1496ae6ea0SThomas Gleixner #ifndef BOOT_BOOT_H
1596ae6ea0SThomas Gleixner #define BOOT_BOOT_H
1696ae6ea0SThomas Gleixner
17d594aa02SAshish Kalra #define STACK_SIZE 1024 /* Minimum number of bytes for stack */
186b6815c6SH. Peter Anvin
1996ae6ea0SThomas Gleixner #ifndef __ASSEMBLY__
2096ae6ea0SThomas Gleixner
21c0891ac1SAlexey Dobriyan #include <linux/stdarg.h>
2296ae6ea0SThomas Gleixner #include <linux/types.h>
2396ae6ea0SThomas Gleixner #include <linux/edd.h>
24fa76dab9SH. Peter Anvin #include <asm/setup.h>
2566928b4eSH. Peter Anvin #include <asm/asm.h>
26c2dcfde8SH. Peter Anvin #include "bitops.h"
276238b47bSH. Peter Anvin #include "ctype.h"
28dd78b973SKees Cook #include "cpuflags.h"
29eb4ea1aeSKirill A. Shutemov #include "io.h"
307b27718bSJoerg Roedel
3196ae6ea0SThomas Gleixner /* Useful macros */
321b72691cSAndi Kleen #define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
331b72691cSAndi Kleen
3496ae6ea0SThomas Gleixner extern struct setup_header hdr;
3596ae6ea0SThomas Gleixner extern struct boot_params boot_params;
3696ae6ea0SThomas Gleixner
37fa97bdf9SPekka Enberg #define cpu_relax() asm volatile("rep; nop")
38fa97bdf9SPekka Enberg
io_delay(void)3996ae6ea0SThomas Gleixner static inline void io_delay(void)
4096ae6ea0SThomas Gleixner {
4196ae6ea0SThomas Gleixner const u16 DELAY_PORT = 0x80;
42eb4ea1aeSKirill A. Shutemov outb(0, DELAY_PORT);
4396ae6ea0SThomas Gleixner }
4496ae6ea0SThomas Gleixner
4596ae6ea0SThomas Gleixner /* These functions are used to reference data in other segments. */
4696ae6ea0SThomas Gleixner
ds(void)4796ae6ea0SThomas Gleixner static inline u16 ds(void)
4896ae6ea0SThomas Gleixner {
4996ae6ea0SThomas Gleixner u16 seg;
5096ae6ea0SThomas Gleixner asm("movw %%ds,%0" : "=rm" (seg));
5196ae6ea0SThomas Gleixner return seg;
5296ae6ea0SThomas Gleixner }
5396ae6ea0SThomas Gleixner
set_fs(u16 seg)5496ae6ea0SThomas Gleixner static inline void set_fs(u16 seg)
5596ae6ea0SThomas Gleixner {
5696ae6ea0SThomas Gleixner asm volatile("movw %0,%%fs" : : "rm" (seg));
5796ae6ea0SThomas Gleixner }
fs(void)5896ae6ea0SThomas Gleixner static inline u16 fs(void)
5996ae6ea0SThomas Gleixner {
6096ae6ea0SThomas Gleixner u16 seg;
6196ae6ea0SThomas Gleixner asm volatile("movw %%fs,%0" : "=rm" (seg));
6296ae6ea0SThomas Gleixner return seg;
6396ae6ea0SThomas Gleixner }
6496ae6ea0SThomas Gleixner
set_gs(u16 seg)6596ae6ea0SThomas Gleixner static inline void set_gs(u16 seg)
6696ae6ea0SThomas Gleixner {
6796ae6ea0SThomas Gleixner asm volatile("movw %0,%%gs" : : "rm" (seg));
6896ae6ea0SThomas Gleixner }
gs(void)6996ae6ea0SThomas Gleixner static inline u16 gs(void)
7096ae6ea0SThomas Gleixner {
7196ae6ea0SThomas Gleixner u16 seg;
7296ae6ea0SThomas Gleixner asm volatile("movw %%gs,%0" : "=rm" (seg));
7396ae6ea0SThomas Gleixner return seg;
7496ae6ea0SThomas Gleixner }
7596ae6ea0SThomas Gleixner
7696ae6ea0SThomas Gleixner typedef unsigned int addr_t;
7796ae6ea0SThomas Gleixner
rdfs8(addr_t addr)7896ae6ea0SThomas Gleixner static inline u8 rdfs8(addr_t addr)
7996ae6ea0SThomas Gleixner {
80*aeb84412SKees Cook u8 *ptr = (u8 *)absolute_pointer(addr);
8196ae6ea0SThomas Gleixner u8 v;
82*aeb84412SKees Cook asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*ptr));
8396ae6ea0SThomas Gleixner return v;
8496ae6ea0SThomas Gleixner }
rdfs16(addr_t addr)8596ae6ea0SThomas Gleixner static inline u16 rdfs16(addr_t addr)
8696ae6ea0SThomas Gleixner {
87*aeb84412SKees Cook u16 *ptr = (u16 *)absolute_pointer(addr);
8896ae6ea0SThomas Gleixner u16 v;
89*aeb84412SKees Cook asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
9096ae6ea0SThomas Gleixner return v;
9196ae6ea0SThomas Gleixner }
rdfs32(addr_t addr)9296ae6ea0SThomas Gleixner static inline u32 rdfs32(addr_t addr)
9396ae6ea0SThomas Gleixner {
94*aeb84412SKees Cook u32 *ptr = (u32 *)absolute_pointer(addr);
9596ae6ea0SThomas Gleixner u32 v;
96*aeb84412SKees Cook asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*ptr));
9796ae6ea0SThomas Gleixner return v;
9896ae6ea0SThomas Gleixner }
9996ae6ea0SThomas Gleixner
wrfs8(u8 v,addr_t addr)10096ae6ea0SThomas Gleixner static inline void wrfs8(u8 v, addr_t addr)
10196ae6ea0SThomas Gleixner {
102*aeb84412SKees Cook u8 *ptr = (u8 *)absolute_pointer(addr);
103*aeb84412SKees Cook asm volatile("movb %1,%%fs:%0" : "+m" (*ptr) : "qi" (v));
10496ae6ea0SThomas Gleixner }
wrfs16(u16 v,addr_t addr)10596ae6ea0SThomas Gleixner static inline void wrfs16(u16 v, addr_t addr)
10696ae6ea0SThomas Gleixner {
107*aeb84412SKees Cook u16 *ptr = (u16 *)absolute_pointer(addr);
108*aeb84412SKees Cook asm volatile("movw %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
10996ae6ea0SThomas Gleixner }
wrfs32(u32 v,addr_t addr)11096ae6ea0SThomas Gleixner static inline void wrfs32(u32 v, addr_t addr)
11196ae6ea0SThomas Gleixner {
112*aeb84412SKees Cook u32 *ptr = (u32 *)absolute_pointer(addr);
113*aeb84412SKees Cook asm volatile("movl %1,%%fs:%0" : "+m" (*ptr) : "ri" (v));
11496ae6ea0SThomas Gleixner }
11596ae6ea0SThomas Gleixner
rdgs8(addr_t addr)11696ae6ea0SThomas Gleixner static inline u8 rdgs8(addr_t addr)
11796ae6ea0SThomas Gleixner {
118*aeb84412SKees Cook u8 *ptr = (u8 *)absolute_pointer(addr);
11996ae6ea0SThomas Gleixner u8 v;
120*aeb84412SKees Cook asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*ptr));
12196ae6ea0SThomas Gleixner return v;
12296ae6ea0SThomas Gleixner }
rdgs16(addr_t addr)12396ae6ea0SThomas Gleixner static inline u16 rdgs16(addr_t addr)
12496ae6ea0SThomas Gleixner {
125*aeb84412SKees Cook u16 *ptr = (u16 *)absolute_pointer(addr);
12696ae6ea0SThomas Gleixner u16 v;
127*aeb84412SKees Cook asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
12896ae6ea0SThomas Gleixner return v;
12996ae6ea0SThomas Gleixner }
rdgs32(addr_t addr)13096ae6ea0SThomas Gleixner static inline u32 rdgs32(addr_t addr)
13196ae6ea0SThomas Gleixner {
132*aeb84412SKees Cook u32 *ptr = (u32 *)absolute_pointer(addr);
13396ae6ea0SThomas Gleixner u32 v;
134*aeb84412SKees Cook asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*ptr));
13596ae6ea0SThomas Gleixner return v;
13696ae6ea0SThomas Gleixner }
13796ae6ea0SThomas Gleixner
wrgs8(u8 v,addr_t addr)13896ae6ea0SThomas Gleixner static inline void wrgs8(u8 v, addr_t addr)
13996ae6ea0SThomas Gleixner {
140*aeb84412SKees Cook u8 *ptr = (u8 *)absolute_pointer(addr);
141*aeb84412SKees Cook asm volatile("movb %1,%%gs:%0" : "+m" (*ptr) : "qi" (v));
14296ae6ea0SThomas Gleixner }
wrgs16(u16 v,addr_t addr)14396ae6ea0SThomas Gleixner static inline void wrgs16(u16 v, addr_t addr)
14496ae6ea0SThomas Gleixner {
145*aeb84412SKees Cook u16 *ptr = (u16 *)absolute_pointer(addr);
146*aeb84412SKees Cook asm volatile("movw %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
14796ae6ea0SThomas Gleixner }
wrgs32(u32 v,addr_t addr)14896ae6ea0SThomas Gleixner static inline void wrgs32(u32 v, addr_t addr)
14996ae6ea0SThomas Gleixner {
150*aeb84412SKees Cook u32 *ptr = (u32 *)absolute_pointer(addr);
151*aeb84412SKees Cook asm volatile("movl %1,%%gs:%0" : "+m" (*ptr) : "ri" (v));
15296ae6ea0SThomas Gleixner }
15396ae6ea0SThomas Gleixner
15496ae6ea0SThomas Gleixner /* Note: these only return true/false, not a signed return value! */
memcmp_fs(const void * s1,addr_t s2,size_t len)155117780eeSH. Peter Anvin static inline bool memcmp_fs(const void *s1, addr_t s2, size_t len)
15696ae6ea0SThomas Gleixner {
157117780eeSH. Peter Anvin bool diff;
15866928b4eSH. Peter Anvin asm volatile("fs; repe; cmpsb" CC_SET(nz)
15966928b4eSH. Peter Anvin : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len));
16096ae6ea0SThomas Gleixner return diff;
16196ae6ea0SThomas Gleixner }
memcmp_gs(const void * s1,addr_t s2,size_t len)162117780eeSH. Peter Anvin static inline bool memcmp_gs(const void *s1, addr_t s2, size_t len)
16396ae6ea0SThomas Gleixner {
164117780eeSH. Peter Anvin bool diff;
16566928b4eSH. Peter Anvin asm volatile("gs; repe; cmpsb" CC_SET(nz)
16666928b4eSH. Peter Anvin : CC_OUT(nz) (diff), "+D" (s1), "+S" (s2), "+c" (len));
16796ae6ea0SThomas Gleixner return diff;
16896ae6ea0SThomas Gleixner }
16996ae6ea0SThomas Gleixner
17096ae6ea0SThomas Gleixner /* Heap -- available for dynamic lists. */
17196ae6ea0SThomas Gleixner extern char _end[];
17296ae6ea0SThomas Gleixner extern char *HEAP;
17396ae6ea0SThomas Gleixner extern char *heap_end;
17496ae6ea0SThomas Gleixner #define RESET_HEAP() ((void *)( HEAP = _end ))
__get_heap(size_t s,size_t a,size_t n)17596ae6ea0SThomas Gleixner static inline char *__get_heap(size_t s, size_t a, size_t n)
17696ae6ea0SThomas Gleixner {
17796ae6ea0SThomas Gleixner char *tmp;
17896ae6ea0SThomas Gleixner
17996ae6ea0SThomas Gleixner HEAP = (char *)(((size_t)HEAP+(a-1)) & ~(a-1));
18096ae6ea0SThomas Gleixner tmp = HEAP;
18196ae6ea0SThomas Gleixner HEAP += s*n;
18296ae6ea0SThomas Gleixner return tmp;
18396ae6ea0SThomas Gleixner }
18496ae6ea0SThomas Gleixner #define GET_HEAP(type, n) \
18596ae6ea0SThomas Gleixner ((type *)__get_heap(sizeof(type),__alignof__(type),(n)))
18696ae6ea0SThomas Gleixner
heap_free(size_t n)187e6e1ace9SH. Peter Anvin static inline bool heap_free(size_t n)
18896ae6ea0SThomas Gleixner {
189e6e1ace9SH. Peter Anvin return (int)(heap_end-HEAP) >= (int)n;
19096ae6ea0SThomas Gleixner }
19196ae6ea0SThomas Gleixner
19296ae6ea0SThomas Gleixner /* copy.S */
19396ae6ea0SThomas Gleixner
19496ae6ea0SThomas Gleixner void copy_to_fs(addr_t dst, void *src, size_t len);
19596ae6ea0SThomas Gleixner void *copy_from_fs(void *dst, addr_t src, size_t len);
19696ae6ea0SThomas Gleixner void copy_to_gs(addr_t dst, void *src, size_t len);
19796ae6ea0SThomas Gleixner void *copy_from_gs(void *dst, addr_t src, size_t len);
19896ae6ea0SThomas Gleixner
19996ae6ea0SThomas Gleixner /* a20.c */
20096ae6ea0SThomas Gleixner int enable_a20(void);
20196ae6ea0SThomas Gleixner
20296ae6ea0SThomas Gleixner /* apm.c */
20396ae6ea0SThomas Gleixner int query_apm_bios(void);
20496ae6ea0SThomas Gleixner
2057a734e7dSH. Peter Anvin /* bioscall.c */
2067a734e7dSH. Peter Anvin struct biosregs {
2077a734e7dSH. Peter Anvin union {
2087a734e7dSH. Peter Anvin struct {
2097a734e7dSH. Peter Anvin u32 edi;
2107a734e7dSH. Peter Anvin u32 esi;
2117a734e7dSH. Peter Anvin u32 ebp;
2127a734e7dSH. Peter Anvin u32 _esp;
2137a734e7dSH. Peter Anvin u32 ebx;
2147a734e7dSH. Peter Anvin u32 edx;
2157a734e7dSH. Peter Anvin u32 ecx;
2167a734e7dSH. Peter Anvin u32 eax;
2177a734e7dSH. Peter Anvin u32 _fsgs;
2187a734e7dSH. Peter Anvin u32 _dses;
2197a734e7dSH. Peter Anvin u32 eflags;
2207a734e7dSH. Peter Anvin };
2217a734e7dSH. Peter Anvin struct {
2227a734e7dSH. Peter Anvin u16 di, hdi;
2237a734e7dSH. Peter Anvin u16 si, hsi;
2247a734e7dSH. Peter Anvin u16 bp, hbp;
2257a734e7dSH. Peter Anvin u16 _sp, _hsp;
2267a734e7dSH. Peter Anvin u16 bx, hbx;
2277a734e7dSH. Peter Anvin u16 dx, hdx;
2287a734e7dSH. Peter Anvin u16 cx, hcx;
2297a734e7dSH. Peter Anvin u16 ax, hax;
2307a734e7dSH. Peter Anvin u16 gs, fs;
2317a734e7dSH. Peter Anvin u16 es, ds;
2327a734e7dSH. Peter Anvin u16 flags, hflags;
2337a734e7dSH. Peter Anvin };
2347a734e7dSH. Peter Anvin struct {
2357a734e7dSH. Peter Anvin u8 dil, dih, edi2, edi3;
2367a734e7dSH. Peter Anvin u8 sil, sih, esi2, esi3;
2377a734e7dSH. Peter Anvin u8 bpl, bph, ebp2, ebp3;
2387a734e7dSH. Peter Anvin u8 _spl, _sph, _esp2, _esp3;
2397a734e7dSH. Peter Anvin u8 bl, bh, ebx2, ebx3;
2407a734e7dSH. Peter Anvin u8 dl, dh, edx2, edx3;
2417a734e7dSH. Peter Anvin u8 cl, ch, ecx2, ecx3;
2427a734e7dSH. Peter Anvin u8 al, ah, eax2, eax3;
2437a734e7dSH. Peter Anvin };
2447a734e7dSH. Peter Anvin };
2457a734e7dSH. Peter Anvin };
2467a734e7dSH. Peter Anvin void intcall(u8 int_no, const struct biosregs *ireg, struct biosregs *oreg);
2477a734e7dSH. Peter Anvin
24896ae6ea0SThomas Gleixner /* cmdline.c */
2493db07e70SYinghai Lu int __cmdline_find_option(unsigned long cmdline_ptr, const char *option, char *buffer, int bufsize);
2503db07e70SYinghai Lu int __cmdline_find_option_bool(unsigned long cmdline_ptr, const char *option);
cmdline_find_option(const char * option,char * buffer,int bufsize)251f4ed2877SYinghai Lu static inline int cmdline_find_option(const char *option, char *buffer, int bufsize)
252f4ed2877SYinghai Lu {
2533db07e70SYinghai Lu unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;
25416a4baa6SYinghai Lu
25516a4baa6SYinghai Lu if (cmd_line_ptr >= 0x100000)
25616a4baa6SYinghai Lu return -1; /* inaccessible */
25716a4baa6SYinghai Lu
25816a4baa6SYinghai Lu return __cmdline_find_option(cmd_line_ptr, option, buffer, bufsize);
259f4ed2877SYinghai Lu }
260f4ed2877SYinghai Lu
cmdline_find_option_bool(const char * option)261f4ed2877SYinghai Lu static inline int cmdline_find_option_bool(const char *option)
262f4ed2877SYinghai Lu {
2633db07e70SYinghai Lu unsigned long cmd_line_ptr = boot_params.hdr.cmd_line_ptr;
26416a4baa6SYinghai Lu
26516a4baa6SYinghai Lu if (cmd_line_ptr >= 0x100000)
26616a4baa6SYinghai Lu return -1; /* inaccessible */
26716a4baa6SYinghai Lu
26816a4baa6SYinghai Lu return __cmdline_find_option_bool(cmd_line_ptr, option);
269f4ed2877SYinghai Lu }
270f4ed2877SYinghai Lu
27196ae6ea0SThomas Gleixner /* cpu.c, cpucheck.c */
27296ae6ea0SThomas Gleixner int check_cpu(int *cpu_level_ptr, int *req_level_ptr, u32 **err_flags_ptr);
273e4a84be6SDave Hansen int check_knl_erratum(void);
27496ae6ea0SThomas Gleixner int validate_cpu(void);
27596ae6ea0SThomas Gleixner
276f4ed2877SYinghai Lu /* early_serial_console.c */
277f4ed2877SYinghai Lu extern int early_serial_base;
278f4ed2877SYinghai Lu void console_init(void);
279f4ed2877SYinghai Lu
28096ae6ea0SThomas Gleixner /* edd.c */
28196ae6ea0SThomas Gleixner void query_edd(void);
28296ae6ea0SThomas Gleixner
28396ae6ea0SThomas Gleixner /* header.S */
28496ae6ea0SThomas Gleixner void __attribute__((noreturn)) die(void);
28596ae6ea0SThomas Gleixner
28696ae6ea0SThomas Gleixner /* memory.c */
287e8eeb3c8SJordan Borgner void detect_memory(void);
28896ae6ea0SThomas Gleixner
28996ae6ea0SThomas Gleixner /* pm.c */
29096ae6ea0SThomas Gleixner void __attribute__((noreturn)) go_to_protected_mode(void);
29196ae6ea0SThomas Gleixner
29296ae6ea0SThomas Gleixner /* pmjump.S */
29396ae6ea0SThomas Gleixner void __attribute__((noreturn))
29496ae6ea0SThomas Gleixner protected_mode_jump(u32 entrypoint, u32 bootparams);
29596ae6ea0SThomas Gleixner
29696ae6ea0SThomas Gleixner /* printf.c */
29796ae6ea0SThomas Gleixner int sprintf(char *buf, const char *fmt, ...);
29896ae6ea0SThomas Gleixner int vsprintf(char *buf, const char *fmt, va_list args);
29996ae6ea0SThomas Gleixner int printf(const char *fmt, ...);
30096ae6ea0SThomas Gleixner
3017a734e7dSH. Peter Anvin /* regs.c */
3027a734e7dSH. Peter Anvin void initregs(struct biosregs *regs);
3037a734e7dSH. Peter Anvin
30496ae6ea0SThomas Gleixner /* string.c */
30596ae6ea0SThomas Gleixner int strcmp(const char *str1, const char *str2);
306fa97bdf9SPekka Enberg int strncmp(const char *cs, const char *ct, size_t count);
30796ae6ea0SThomas Gleixner size_t strnlen(const char *s, size_t maxlen);
30896ae6ea0SThomas Gleixner unsigned int atou(const char *s);
309fa97bdf9SPekka Enberg unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base);
310062fe8feSFred Chen size_t strlen(const char *s);
311f2844249SDave Jiang char *strchr(const char *s, int c);
31296ae6ea0SThomas Gleixner
31396ae6ea0SThomas Gleixner /* tty.c */
31496ae6ea0SThomas Gleixner void puts(const char *);
31596ae6ea0SThomas Gleixner void putchar(int);
31696ae6ea0SThomas Gleixner int getchar(void);
31796ae6ea0SThomas Gleixner void kbd_flush(void);
31896ae6ea0SThomas Gleixner int getchar_timeout(void);
31996ae6ea0SThomas Gleixner
32096ae6ea0SThomas Gleixner /* video.c */
32196ae6ea0SThomas Gleixner void set_video(void);
32296ae6ea0SThomas Gleixner
323e44b7b75SPavel Machek /* video-mode.c */
324e44b7b75SPavel Machek int set_mode(u16 mode);
325e44b7b75SPavel Machek int mode_defined(u16 mode);
326e44b7b75SPavel Machek void probe_cards(int unsafe);
327e44b7b75SPavel Machek
32896ae6ea0SThomas Gleixner /* video-vesa.c */
32996ae6ea0SThomas Gleixner void vesa_store_edid(void);
33096ae6ea0SThomas Gleixner
33196ae6ea0SThomas Gleixner #endif /* __ASSEMBLY__ */
33296ae6ea0SThomas Gleixner
33396ae6ea0SThomas Gleixner #endif /* BOOT_BOOT_H */
334