¿Cómo se ejecutan los sistemas operativos ... sin tener un sistema operativo en el que ejecutar?


167

Tengo mucha curiosidad ahora. Soy un programador de Python, y esta pregunta me dejó perplejo: escribes un sistema operativo. ¿Cómo lo ejecutas? Tiene que ejecutarse de alguna manera, y de esa manera está dentro de otro sistema operativo?

¿Cómo puede ejecutarse una aplicación sin estar en un sistema operativo? ¿Cómo le dice a la computadora que ejecute, digamos, C, y ejecute estos comandos en la pantalla, si no tiene un sistema operativo para ejecutar?

¿Tiene que ver con un núcleo UNIX? Si es así, ¿qué es un núcleo Unix, o un núcleo en general?

Estoy seguro de que los sistemas operativos son más complicados que eso, pero ¿cómo funciona?


14
Estoy bastante seguro de que para eso es un BIOS: es un sistema operativo realmente pequeño que inicia el funcionamiento del sistema operativo más grande.
sevenseacat

64
Un sistema operativo es conveniente , pero no necesita uno para ejecutar programas en una computadora.
Andres F.

10
Es perfectamente posible incluso escribir software que no sea OS sin un SO. Muchos intérpretes de Forth corrían tradicionalmente sin un sistema operativo (o se podría decir que eran sistemas operativos). Ni siquiera es tan difícil. Si conoce C, puede disfrutar escribiendo un programa de este tipo (un juego pequeño, tal vez) como un ejercicio de aprendizaje.
Max

44
Esta confusión es uno de los costos de los maravillosos, seguros y altamente abstractos sistemas informáticos que usamos en estos días: las personas pueden ser programadores muy buenos y competentes y no saber ni siquiera los fundamentos sobre cómo funciona la computadora. ¿Qué tan bajo quieres ir? Para muy bajo, pero aún por encima de la física ver ¿Cómo se programaron los primeros microprocesadores? en Electrónica.SE.
dmckee

2
La programación se realizó antes de la invención del concepto actual del sistema operativo. Obviamente, algo a ese nivel es lo que inicia el sistema operativo. Los sistemas operativos son de arranque. Esto suele mencionarse al menos en un programa de 4 años de CS en algún momento, ya que la mayoría requiere un curso de teoría informática de sistemas operativos.
Aparejo

Respuestas:


263

Hay muchos sitios web que pasan por el proceso de arranque (como How Computers Boot Up ). En pocas palabras, es un proceso de varias etapas que sigue construyendo el sistema poco a poco hasta que finalmente puede iniciar los procesos del sistema operativo.

Comienza con el firmware de la placa base que intenta poner en funcionamiento la CPU. Luego carga el BIOS, que es como un mini sistema operativo que pone en funcionamiento el otro hardware. Una vez hecho esto, busca un dispositivo de arranque (disco, CD, etc.) y, una vez encontrado, localiza el MBR (registro de arranque maestro) y lo carga en la memoria y lo ejecuta. Es este pequeño fragmento de código que luego sabe cómo inicializar e iniciar el sistema operativo (u otros cargadores de arranque a medida que las cosas se vuelven más complicadas). Es en este punto que cosas como el núcleo se cargarán y comenzarán a ejecutarse.

¡Es increíble que funcione!


108
+1 para la oración final.
un CVn

39
Hay una razón por la que se llama "arranque"; el término es corto para "bootstrapping", como en "tirarse de sus bootstraps".
KeithS

55
Hubo un momento en que alguien tenía que teclear o alternar el código de arranque. A veces era un simple salto a la primera instrucción de un programa en ROM. Otras veces era código para leer desde un dispositivo y saltar a la primera instrucción del programa en los datos que se leían. Las cosas son mucho más simples ahora.
BillThor


15
@BillThor: Donde por "mucho más simple" usted, por supuesto, quiere decir "mucho más complicado". Son simplemente más simples de usar .
Raphael Schweikert

173

Un sistema operativo "bare metal" no funciona dentro de nada. Ejecuta el conjunto completo de instrucciones en la máquina física y tiene acceso a toda la memoria física, todos los registros del dispositivo y todas las instrucciones privilegiadas, incluidas las que controlan el hardware de soporte de memoria virtual.

(Si el sistema operativo se ejecuta en una máquina virtual, puede pensar que se encuentra en la misma situación que la anterior. La diferencia es que ciertas cosas son emuladas o de alguna otra manera manejadas por el hipervisor; es decir, el nivel que ejecuta las máquinas virtuales .)

De todos modos, aunque el sistema operativo podría implementarse en (por ejemplo) C, no tendrá todas las bibliotecas C normales disponibles. En particular, no tendrá las bibliotecas 'stdio' normales. Por el contrario, implementará (por ejemplo) un controlador de dispositivo de disco que le permite leer y escribir bloques de disco. Implementará un sistema de archivos en la parte superior de la capa de bloque de disco, y además implementará las llamadas al sistema que hacen las bibliotecas de tiempo de ejecución de una aplicación de usuario para (por ejemplo) crear, leer y escribir archivos ... y así sucesivamente.

¿Cómo puede ejecutarse una aplicación sin estar en un sistema operativo?

Debe ser un tipo especial de aplicación (por ejemplo, un sistema operativo) que sepa cómo interactuar directamente con el hardware de E / S, etc.

¿Cómo le dice a la computadora que ejecute, digamos, C, y ejecute estos comandos en la pantalla, si no tiene un sistema operativo para ejecutar?

Usted no

La aplicación (que fue por el argumento escrito en C) se compila y se vincula en alguna otra máquina para dar una imagen de código nativo. Luego, la imagen se escribe en el disco duro en un lugar donde el BIOS pueda encontrarla. El BIOS carga la imagen en la memoria y ejecuta una instrucción para saltar al punto de entrada de la aplicación.

No hay (típicamente) ningún "ejecutando C y ejecutando comandos" en la aplicación a menos que sea un sistema operativo completo. Y en ese caso, es responsabilidad del sistema operativo implementar toda la infraestructura requerida para que esto suceda. Sin magia Solo mucho código.

La respuesta de Bill cubre el arranque, que es el proceso en el que se pasa de una máquina apagada a una máquina en la que el sistema operativo normal está en funcionamiento. Sin embargo, vale la pena señalar que cuando el BIOS completa sus tareas, (por lo general) cede el control completo del hardware al sistema operativo principal, y no desempeña ningún papel adicional, hasta el próximo reinicio del sistema. El sistema operativo principal ciertamente no se ejecuta "dentro" del BIOS en el sentido convencional.

¿Tiene que ver con un núcleo UNIX? Si es así, ¿qué es un núcleo Unix, o un núcleo en general?

Si lo hace

El núcleo UNIX es el núcleo del sistema operativo UNIX. Es la parte de UNIX que hace todo el "metal desnudo" descrito anteriormente.

La idea de un "núcleo" es que intente separar el software del sistema en elementos básicos (que requieren acceso al dispositivo físico, toda la memoria, etc.) y elementos no básicos. El núcleo consta de las cosas principales.

En realidad, la distinción entre kernel / core y non-kernel / non-core es más complicada que eso. Y se ha debatido mucho sobre lo que realmente pertenece a un núcleo y lo que no. (Busque micro-kernel por ejemplo).


66
Respuesta fenomenal. Te daría varios votos más si es posible.
weberc2

77
Muchas buenas respuestas aquí, así que lo agregaré como un comentario, ya que nadie ha mencionado esto hasta ahora: una de las características clave en un sistema operativo es permitir que varias aplicaciones se ejecuten "simultáneamente" desde la perspectiva del usuario. La capacidad de programar procesos y proteger los procesos para que no alteren el comportamiento de los demás, generalmente son características que solo se encuentran en un sistema operativo, y no en el firmware o BIOS.
Sean Barbeau

2
The idea of a "kernel" is that you try to separate the system software into core stuffFácil de recordar al señalar que el término kerneles del alemán Kern, que significa núcleo / núcleo.
deed02392

1
Me encanta esta respuesta aquí porque menciona que está compilado y enlazado código binario que no se ejecuta C.
Travis Pessetto

3
"Alejarse de eso hizo que los usuarios de PC fueran menos inteligentes". - No menos inteligente ... menos informático. También se podría decir que aumentó la cantidad de usuarios de PC.
Stephen C

62

Al principio no había energía en la CPU.

Y el Hombre dijo "que haya energía", y la CPU comenzó a leer de una dirección dada en la memoria y ejecutar la instrucción que estaba presente allí. Luego el siguiente y así sucesivamente hasta el final del poder.

Este fue el arranque. Su tarea consistía en cargar otra pieza de software para obtener acceso al entorno, donde estaba el software principal, y cargarlo.

Finalmente, una pantalla amigable lo invitó a iniciar sesión.


58
Esta respuesta debe trasladarse a christianity.stackexchange.com
Coomie

66
qué es "una dirección dada" de dónde viene. Perdón por interpretar a Charles Darwin aquí.
Midhat

77
@Midhat: la primera dirección que debe obtener la CPU está cableada en su interior. Por lo general, es 0.
mouviciel

17
... Y el séptimo día, el Hombre descansó con sus juegos
canadiense Luke el

99
@mouviciel La dirección en la memoria es 0x7C00para cualquier x86arquitectura compatible y primero tiene que ser completada por el BIOS, que generalmente carga el primer sector de cualquier dispositivo de arranque que prefiera ... Buena respuesta: -7
Tobias Kienzler

29

Lamento llegar tarde, pero lo describiré como tal:

  • La placa base recibe energía.

  • Los circuitos de temporización comienzan y se estabilizan si es necesario, basándose únicamente en sus características eléctricas. Algunos dispositivos más nuevos pueden usar un microprocesador o secuenciador muy limitado.

    Cabe señalar que muchas [sic] de las cosas como "los circuitos de temporización comienzan y se estabilizan si es necesario" realmente ya no ocurren en el hardware. Una gran cantidad de ese trabajo es en realidad un software extremadamente especializado que se ejecuta en subprocesadores / secuenciadores muy limitados.

    - Jkerian a las 5:20 el 25 de octubre

  • Se le da energía a la CPU y la RAM.

  • La CPU carga (según su cableado interno) datos del BIOS. En algunas máquinas, el BIOS puede duplicarse en la RAM y luego ejecutarse desde allí, pero eso es raro en el IIRC.

    Cuando se activa, las CPU compatibles con x86 comienzan en la dirección 0xFFFFFFF0 en el espacio de direcciones ...

    -Micheal Steil, 17 errores cometidos por Microsoft en el sistema de seguridad de Xbox ( archivo )

  • El BIOS realiza llamadas a los puertos y direcciones de hardware utilizados por la placa base para el disco y otras E / S de hardware y hace girar discos, hace que el resto de la RAM funcione, entre otras cosas.

  • El código del BIOS (a través de la configuración de CMOS, almacenada en el hardware) usa comandos IDE o SATA de bajo nivel para leer el sector de arranque de cada disco, en un orden especificado por el CMOS o un usuario anula con un menú.

  • El primer disco con un sector de arranque ejecuta su sector de arranque. Este sector de arranque es ensamblado que tiene instrucciones para cargar más datos del disco, cargar una NTLDRetapa posterior más grande GRUB, etc.

  • Finalmente, el gestor de arranque ejecuta el código de máquina del sistema operativo, directa o indirectamente a través de la carga en cadena cargando un sector de arranque desde una ubicación alternativa o desplazada.

Luego obtienes un pánico amigable del núcleo, un pingüino sofocado, o tu disco se detiene debido a un golpe en la cabeza. =) En el escenario alternativo, su kernel configura tablas de proceso, estructuras en memoria y monta discos, carga controladores, módulos y una GUI o conjunto de servicios (si está en un servidor). Luego, los programas se ejecutan a medida que se leen sus encabezados, y su ensamblaje se lleva a la memoria y se asigna en consecuencia.


2
Cabe señalar que muchas cosas como "los circuitos de temporización comienzan y se estabilizan si es necesario" ya no suceden en el hardware. Una gran cantidad de ese trabajo es en realidad un software extremadamente especializado que se ejecuta en subprocesadores / secuenciadores muy limitados. - Un ingeniero de firmware de vecindario amigable
jkerian

@jkerian ¿Te importa que haya citado tu comentario en mi publicación?
ζ--

je, no del todo.
jkerian 01 de

BIOS no es un sistema operativo. BIOS es la abreviatura de Basic Input / Output System, y eso es lo que hace BIOS. Permite a los programadores usar recursos de bajo nivel con controladores proporcionados por el fabricante. Cuando el sistema operativo entra en modo protegido (32 bits) o largo (64 bits), el BIOS ya no está disponible y el sistema operativo utiliza sus propios controladores que básicamente reemplazan la funcionalidad que el BIOS proporcionaba en los niveles "inferiores". Los sistemas operativos modernos, por ejemplo, Linux y Windows, usan el BIOS solo para detectar secciones de RAM utilizables y cargar su propio cargador más avanzado que puede cargar los controladores necesarios.
Hannes Karppila

1
@HannesKarppila Actualizado; Sin embargo, esto tiene aproximadamente cuatro años y ya no estoy activo en este sitio.
ζ--

15

Hay muchas buenas respuestas, pero quería agregar esto: usted mencionó que proviene de un fondo de Python. Python es un lenguaje no interpretado (o "interpilado" o lo que sea, al menos en los casos de uso típicos de CPython). Esto significa que tiene otro software (el intérprete de Python) mirando la fuente y ejecutándola de alguna manera. Este es un modelo excelente y permite lenguajes de alto nivel bastante agradables y bien abstraídos del hardware real. Lo malo es que siempre necesita este software de intérprete primero.

Dicho software de interpretación, por lo general, está escrito en un lenguaje que se compila en código máquina, por ejemplo, C o C ++. El código de máquina es lo que la CPU puede manejar. Lo que puede hacer una CPU es leer algunos bytes de la memoria y, según los valores de bytes, comenzar una operación específica. Entonces, una secuencia de bytes es un comando para cargar algunos datos de la memoria en un registro, otra secuencia para agregar dos valores, otra para almacenar el valor de un registro en la memoria principal y pronto (un registro es un área de memoria especial que es parte de la CPU donde puede funcionar mejor), la mayoría de estos comandos son bastante bajos en ese nivel. La lectura humana de estas instrucciones de código de máquina es el código del ensamblador. Este código de máquina, básicamente, es lo que se almacena en archivos .exe o.com en Windows o dentro de los archivos binarios de Linux / Unix.

Ahora, si se inicia una computadora, es tonto, aunque tiene algunos cables que leerán las instrucciones del código de la máquina. En una PC, esto generalmente (actualmente) es un chip EEPROM en la placa base que contiene el BIOS (sistema de salida de entrada básico), este sistema no puede hacer mucho, puede facilitar el acceso a algún hardware, etc. y luego hacer una operación clave: vaya a arranque y copie los primeros bytes (también conocido como el registro de arranque maestro, MBR) en la memoria y luego diga a la CPU "aquí está su programa", la CPU tratará esos bytes allí como código de máquina y lo ejecutará. Por lo general, este es un cargador de sistema operativo que cargará el kernel con algunos parámetros y luego entregará el control a ese kernel, que luego cargará todos sus controladores para acceder a todo el hardware, cargar algún programa de escritorio o shell o lo que sea y permitir al usuario iniciar sesión y usa el sistema.


66
"interpilado"? Nunca he escuchado ese término antes.
Bryan Oakley

3
Ese término se usó hace 5 años más o menos, para describir intérpretes "modernos" que tienen una fase de compilación distinta que es independiente de la ejecución. No tengo idea si este término sobrevivió en alguna parte ;-)
johannes

1
"no interpretado"? Nunca he escuchado ese término antes.
Cole Johnson

12

Usted pregunta "¿Cómo puede ejecutarse una aplicación sin estar en un sistema operativo?". La respuesta fácil es "un sistema operativo no es una aplicación". Si bien un SO se puede crear con las mismas herramientas que una aplicación, y estar hecho de la misma materia prima, no son lo mismo. Un sistema operativo no tiene que jugar con las mismas reglas que una aplicación.

OTOH, puede pensar en el hardware y firmware reales como el "SO" en el que se ejecuta la "aplicación" del SO. El hardware es un sistema operativo muy simple: sabe cómo ejecutar las instrucciones escritas en el código de la máquina y sabe que cuando se inicia debe buscar una dirección de memoria muy específica para su primera instrucción. Entonces, se inicia y luego ejecuta inmediatamente la primera instrucción, seguida de la segunda, y así sucesivamente.

Por lo tanto, el sistema operativo es simplemente un código de máquina que existe en una ubicación conocida y que puede interactuar directamente con el hardware.


1
+1 Creo que esta es la mejor respuesta. En términos de abstracciones, creo que lo estás logrando en los niveles correctos.
Saludo Sangha

6

La respuesta a su pregunta requiere el conocimiento de cómo se ve el código nativo (para CPU) y cómo es interpretado por la CPU.

Por lo general, todo el proceso de compilación se basa en traducir cosas que escribe en C, Pascal o incluso Python (usando pypy) y C # en cosas que la CPU entiende, es decir, instrucciones simples como "almacenar algo en [dirección de memoria]", "agregar números almacenados en registros eax y ebx "," call function foo "," compare eax con 10 ". Esas instrucciones, ejecutadas una por una, hacen las cosas que querías hacer con tu código.

Ahora piense en esto: ¡realmente no necesita un sistema operativo para ejecutar este código nativo! Todo lo que necesita es cargar este código en la memoria y decirle a la CPU que está allí y que desea que se ejecute. Sin embargo, no te preocupes demasiado por eso. Ese es el trabajo del que debe preocuparse el BIOS: carga su código (solo uno y un sector), justo después de que se inicia la CPU, bajo la dirección física 0x7C00. Luego, la CPU comienza a ejecutar este sector (512 B) de su código. ¡Y puedes hacer lo que imagines! Sin, por supuesto, ningún soporte del sistema operativo. Eso es porque USTED es el sistema operativo. Genial, ¿eh? ¡Sin biblioteca estándar, sin impulso, sin python, sin programas, sin controladores! Tienes que escribir todo por ti mismo.

¿Y cómo te comunicas con el hardware? Bueno, tienes dos opciones:

  1. Permanece dentro del "Modo real": modo de ejecución de CPU con solo 1 MB de memoria (e incluso menos), sin funciones avanzadas de CPU como extensiones de CPU, protección de memoria, multitarea; Código ejecutable de 16 bits, modo de direccionamiento antiguo ... Pero con algunas rutinas proporcionadas por BIOS, que incluyen salida de pantalla simple, soporte de teclado, E / S de disco y administración de energía. En una palabra, estás de vuelta en tiempos de MS-DOS y CPU de 16 bits.
  2. Vaya a "Modo protegido" con todas las funciones que tiene su CPU, toda la memoria que ha instalado, etc. Pero en el Modo protegido, ESTÁ completamente solo y tiene que hacer TODO usted mismo (y se comunica con el hardware utilizando instrucciones de "entrada" y "salida" para ingresar / emitir datos a los puertos de E / S y usar interrupciones. / O). ¿Tengo que decir que todos los sistemas operativos desde Windows 95 y el primer Linux eligen esta opción?

Ahora estás preguntando qué es el núcleo. En breve, el núcleo es todo lo que no ve y experimenta directamente. Gestiona, junto con los controladores, todo, desde su teclado hasta casi todas las piezas de hardware dentro de su PC. Te comunicas con él por shell gráfico o terminal. O por funciones dentro de su código, ahora ejecutadas, por suerte, con soporte del sistema operativo.

Para una mejor comprensión, puedo darle un consejo: intente escribir su propio sistema operativo. Incluso si va a escribir "Hola mundo" en la pantalla.


3

Existen algunas diferencias en cuanto al funcionamiento de un sistema operativo que dependen mucho del sistema. Para ser útil, un sistema debe tener un comportamiento predecible al inicio, como "comenzar a ejecutar en la dirección X". Para los sistemas que tienen un almacenamiento no volátil (como la memoria Flash) mapeado en su espacio de programa, esto es bastante fácil ya que solo se asegura de colocar el código de inicio en la ubicación correcta dentro del espacio de programa del procesador. Esto es extremadamente común para los microcontroladores. Algunos sistemas tienen que recuperar sus programas de inicio desde otra ubicación antes de ejecutarlo. Estos sistemas tendrán algunas operaciones cableadas (o casi cableadas) en ellas. Hay algunos procesadores que recuperan su código de inicio a través de i2c desde otro chip,

Los sistemas que utilizan la familia de procesadores x86 suelen utilizar un proceso de arranque de varias etapas que es bastante complejo debido a su evolución y problemas de compatibilidad con versiones anteriores. El sistema ejecuta algún firmware (llamado BIOS - Sistema básico de entrada / salida, o similar) que se encuentra en alguna memoria no volátil en la placa base. A veces, parte o la totalidad de este firmware se copia (reubica) en la RAM para que se ejecute más rápido. Este código fue escrito con conocimiento de qué hardware estaría presente y utilizable para el arranque.

El firmware de inicio generalmente se escribe con suposiciones sobre qué hardware estará presente en el sistema. Hace años en una máquina 286 probablemente habría una suposición de que habría un controlador de unidad de disquete en la dirección de E / S X y cargaría el sector 0 a una determinada ubicación de memoria si se le da un determinado conjunto de comandos (y el código en el sector 0 sabe cómo usar las funciones propias del BIOS para cargar más código, y eventualmente se carga suficiente código para ser un SO). En un microcontrolador puede suponerse que hay un puerto serie que funciona con ciertas configuraciones y que debe esperar los comandos (para actualizar el firmware más complejo) durante X cantidad de tiempo antes de continuar con el proceso de arranque.

El proceso exacto de inicio de un sistema dado no es tan importante para usted como saber que difiere en los diferentes sistemas, pero también que todos tienen cosas en común. A menudo, dentro del código de inicio (bootstrapping) cuando se necesita hacer E / S, los dispositivos de E / S se sondean en lugar de depender de interrupciones. Esto se debe a que las interrupciones son complejas, utilice la memoria RAM de la pila (que puede no estar completamente configurada todavía) y no necesita preocuparse por bloquear otras operaciones cuando es la única operación.

Al cargarse por primera vez, el núcleo del sistema operativo (el núcleo es la parte principal de la mayoría de los sistemas operativos) inicialmente actuará de manera muy similar al firmware. Tendrá que ser programado con conocimiento o descubrir hardware presente, configurar algo de RAM como espacio de pila, hacer varias pruebas, configurar varias estructuras de datos, posiblemente descubrir y montar un sistema de archivos, y luego probablemente iniciar algún programa que sea más como los programas que está acostumbrado a escribir (un programa que se basa en un sistema operativo presente).

El código del sistema operativo generalmente se escribe en una mezcla de C y ensamblaje. El primer código para el kernel del sistema operativo probablemente siempre esté en ensamblado y hace cosas como configurar la pila, en la que se basa el código C, y luego llama a una función C. También habrá otro ensamblaje escrito a mano porque algunas operaciones que un sistema operativo debe realizar a menudo no se pueden expresar en C (como cambio de contexto / intercambio de pilas). A menudo, se deben pasar banderas especiales al compilador de C para decirle que no confíe en las bibliotecas estándar que utilizan la mayoría de los programas de C y que no espere que haya unint main(int argc, char *argv[])en el programa. Además, se deben usar opciones de enlazador especiales que la mayoría de los programadores de aplicaciones nunca usan. Esto puede hacer que el programa del kernel espere cargarse en una determinada dirección o configurar cosas para que parezcan que hay variables externas en ciertas ubicaciones a pesar de que esas variables nunca se declararon en ningún código C (esto es útil para E / S mapeadas en memoria o otras ubicaciones especiales de memoria).

Al principio, toda la operación parece mágica, pero después de mirarla y comprender partes de ella, la magia se convierte en un conjunto de programas que requieren mucha más planificación y conocimiento del sistema para su implementación. Sin embargo, depurarlos requiere magia.


3

Para comprender cómo funcionan los sistemas operativos, puede ser útil dividirlos en dos categorías: aquellos que simplemente brindan servicios a las aplicaciones a pedido y aquellos que usan funciones de hardware en la CPU para evitar que las aplicaciones hagan cosas que no deberían. MS-DOS era del estilo anterior; Todas las versiones de Windows desde 3.0 han sido el último estilo (al menos cuando se ejecuta algo más potente que un 8086).

La PC original de IBM con PC-DOS o MS-DOS habría sido un ejemplo del estilo anterior de "SO". Si una aplicación quisiera mostrar un personaje en la pantalla, habría habido algunas formas de hacerlo. Podría llamar a la rutina que le pediría a MS-DOS que la envíe a "salida estándar". Si lo hiciera, MS-DOS comprobaría si la salida se estaba redirigiendo y, si no, llamaría a una rutina almacenada en la ROM (en una colección de rutinas que IBM llamó el Sistema básico de entrada / salida) que mostraría un carácter en el posición del cursor y mueva el cursor ("escribir teletipo"). Esa rutina de BIOS almacenaría un par de bytes en algún lugar en el rango de 0xB800: 0 a 0xB800: 3999; el hardware del Adaptador de gráficos en color buscará repetidamente pares de bytes dentro de ese rango, usando el primer byte de cada par para seleccionar la forma de un personaje y el segundo para seleccionar los colores de primer plano y fondo. Los bytes se obtienen y procesan en señales rojas, verdes y azules, en una secuencia que produce una visualización de texto legible.

Los programas en la PC de IBM podrían mostrar texto usando la rutina de "salida estándar" de DOS, o usando la rutina de "teletipo de escritura" del BIOS, o almacenándola directamente para mostrar la memoria. Muchos programas que necesitaban mostrar mucho texto optaron rápidamente por este último enfoque, ya que podría ser literalmente cientos de veces más rápido que usar las rutinas de DOS. Esto no fue porque las rutinas de DOS y BIOS eran excepcionalmente ineficientes; a menos que la pantalla estuviera en blanco, solo podría escribirse en ciertos momentos. La rutina de BIOS para generar un carácter se diseñó para que se pueda llamar en cualquier momento; Por lo tanto, cada solicitud tenía que comenzar de nuevo esperando el momento adecuado para realizar una operación de escritura. Por el contrario, el código de aplicación que sabía lo que tenía que hacer podría organizarse en torno a las oportunidades disponibles para escribir la pantalla.

Un punto clave aquí es que, si bien el DOS y el BIOS proporcionaron un medio para enviar texto a la pantalla, no había nada particularmente "mágico" en tales habilidades. Una aplicación que quisiera escribir texto en la pantalla podría hacerlo con la misma eficacia, al menos si el hardware de la pantalla funcionara de la manera esperada (si alguien hubiera instalado un Adaptador de pantalla monocromo, que era similar al CGA pero tenía su memoria de caracteres) ubicado en 0xB000: 0000-0xB000: 3999), el BIOS generaría automáticamente caracteres allí; una aplicación que fue programada para funcionar con el MDA o el CGA también podría hacerlo, pero una aplicación que fue programada solo para el CGA sería totalmente inútil en el MDA).

En los sistemas más nuevos, las cosas son un poco diferentes. Los procesadores tienen varios modos de "privilegio". Comienzan en el modo más privilegiado, donde el código puede hacer lo que quiera. Luego pueden cambiar a un modo restringido, donde solo están disponibles rangos seleccionados de memoria o instalaciones de E / S. El código no puede cambiar directamente de un modo restringido a modo privilegiado, pero el procesador ha definido puntos de entrada en modo privilegiado, y el código en modo restringido puede pedirle al procesador que comience a ejecutar código en uno de esos puntos de entrada en modo privilegiado. Además, hay puntos de entrada en modo privilegiado asociados con una serie de operaciones que estarían prohibidas en modo restringido. Supongamos, por ejemplo, que alguien quisiera ejecutar múltiples aplicaciones de MS-DOS simultáneamente, cada una con su propia pantalla. Si las aplicaciones pudieran escribir directamente en el controlador de pantalla a 0xB800: 0, no habría forma de evitar que una aplicación sobrescriba la pantalla de otra aplicación. Por otro lado, un sistema operativo podría ejecutar la aplicación en modo restringido y atrapar cualquier acceso a la memoria de la pantalla; Si descubriera que una aplicación que se suponía que estaba en el "fondo" intentaba escribir 0xB800: 160, podría almacenar los datos en alguna memoria que había guardado como un búfer de pantalla de la aplicación en segundo plano. Si esa aplicación luego se cambia al primer plano, el búfer podría copiarse en la pantalla real. un sistema operativo podría ejecutar la aplicación en modo restringido y atrapar cualquier acceso a la memoria de visualización; Si descubriera que una aplicación que se suponía que estaba en el "fondo" intentaba escribir 0xB800: 160, podría almacenar los datos en alguna memoria que había guardado como un búfer de pantalla de la aplicación en segundo plano. Si esa aplicación luego se cambia al primer plano, el búfer podría copiarse en la pantalla real. un sistema operativo podría ejecutar la aplicación en modo restringido y atrapar cualquier acceso a la memoria de visualización; Si descubriera que una aplicación que se suponía que estaba en el "fondo" intentaba escribir 0xB800: 160, podría almacenar los datos en alguna memoria que había guardado como un búfer de pantalla de la aplicación en segundo plano. Si esa aplicación luego se cambia al primer plano, el búfer podría copiarse en la pantalla real.

Las cosas clave a tener en cuenta son (1) aunque a menudo es útil tener un conjunto estándar de rutinas para realizar diversos servicios estándar como mostrar texto, no hacen nada que una aplicación que se ejecutaba en "modo privilegiado" no pudiera hacer si se programó correctamente para manejar el hardware que se instaló; (2) aunque el sistema operativo evitaría que la mayoría de las aplicaciones que se ejecutan hoy en día realicen tales E / S directamente, un programa que se inicia en modo privilegiado puede hacer lo que quiera y puede establecer las reglas que desee para el modo restringido programas


2

Como dijo Stephen C., no se trata solo de iniciar el sistema operativo, también se trata de cómo se ejecuta, interactúa con el hardware y con el software que se encuentra encima.

Solo agregaré a su respuesta, que es posible que desee echar un vistazo a "Los elementos de los sistemas informáticos" . Es un libro y algunas herramientas que explican cómo interactúan una computadora, un sistema operativo y compiladores. Lo único es que le brinda las herramientas para desarrollar rápidamente su propio sistema operativo en un entorno simulado, ignorando los muchos detalles necesarios para uno real, de modo que pueda comprender los conceptos . Hace un gran trabajo al permitirte ver el bosque en lugar de los árboles.

Si desea obtener más detalles sobre cómo interactúa el sistema operativo con el hardware, consulte Minix .


1

Escribes un sistema operativo. Tiene que ejecutarse de alguna manera, y de esa manera está dentro de otro sistema operativo?

Su aplicación se ejecuta dentro de un sistema operativo. Este sistema operativo proporciona servicios a su aplicación, como abrir un archivo y escribir bytes en él. Estos servicios generalmente se proporcionan a través de llamadas al sistema.

El sistema operativo se ejecuta dentro del hardware. El hardware proporciona servicios al sistema operativo, como configurar la velocidad en baudios de un puerto serie y escribir bytes en él. Estos servicios generalmente se proporcionan a través de registros mapeados en memoria o puertos de E / S.


Para dar un ejemplo muy simplificado de cómo funciona esto:

Su aplicación le dice al sistema operativo que escriba algo en un archivo. Para su aplicación, el sistema operativo proporciona conceptos como archivos y directorios.

En el hardware, estos conceptos no existen. El hardware proporciona conceptos como discos divididos en bloques fijos de 512 bytes. El sistema operativo decide qué bloques usar para su archivo, y algunos otros bloques para metadatos como el nombre del archivo, el tamaño y la ubicación en el disco. Luego le dice al hardware: escriba estos 512 bytes en el sector con este número en el disco con ese número; escriba estos otros 512 bytes en el sector con este número diferente en el disco con ese mismo número; y así.

La forma en que el sistema operativo le dice al hardware que haga eso varía mucho. Una de las funciones de un sistema operativo es proteger las aplicaciones de estas diferencias. Para el ejemplo de disco, en un tipo de hardware, el sistema operativo tendría que escribir el disco y el número de sector en un puerto de E / S, y luego escribir los bytes uno por uno en un puerto de E / S separado. En otro tipo de hardware, el sistema operativo tendría que copiar los 512 bytes completos de un sector en un área de memoria, escribir la ubicación de esa área de memoria en una ubicación de memoria especial y escribir el disco y el número de sector en otro ubicación especial de memoria.


El hardware de gama alta de hoy es extremadamente complicado. Los manuales que dan todos sus detalles de programación son topes de puerta con miles de páginas; por ejemplo, el último manual de CPU de Intel tiene siete volúmenes, con un total de más de 4000 páginas, y eso es solo para la CPU. La mayoría de los otros componentes exponen bloques de memoria o puertos de E / S, que el sistema operativo puede indicarle a la CPU que asigne a las direcciones dentro de su espacio de direcciones. Varios de estos componentes exponen aún más cosas detrás de unos pocos puertos de E / S o direcciones de memoria; Como ejemplo, el RTC (Reloj en tiempo real, el componente que mantiene el tiempo de la computadora mientras está apagado) expone unos cientos de bytes de memoria detrás de un par de puertos de E / S, y ese es un componente muy simple que se remonta a La PC / AT original. Cosas como los discos duros tienen procesadores completamente separados, con el que el sistema operativo se comunica a través de comandos estandarizados. Las GPU son aún más complicadas.

Varias personas en los comentarios anteriores sugirieron el Arduino. Estoy de acuerdo con ellos, es mucho más simple de entender: el ATmega328, que hace todo en el Arduino Uno, excepto exponer el conector USB como puerto serie, tiene un manual con solo unos cientos de páginas. En Arduino, se ejecuta directamente en el hardware, sin sistema operativo en el medio; solo algunas pequeñas rutinas de biblioteca, que no tiene que usar si no lo desea.


1

Ejemplos ejecutables

Técnicamente, un programa que se ejecuta sin un sistema operativo es un sistema operativo. Así que veamos cómo crear y ejecutar algunos minúsculos sistemas operativos hello world.

El código de todos los ejemplos a continuación está presente en este repositorio de GitHub .

Sector de arranque

En x86, lo más simple y de nivel más bajo que puede hacer es crear un Master Boot Sector (MBR) , que es un tipo de sector de arranque , y luego instalarlo en un disco.

Aquí creamos uno con una sola printfllamada:

printf '\364%509s\125\252' > main.img
sudo apt-get install qemu-system-x86
qemu-system-x86_64 -hda main.img

Salir:

ingrese la descripción de la imagen aquí

Probado en Ubuntu 18.04, QEMU 2.11.1.

main.img contiene lo siguiente:

  • \364en octal == 0xf4en hexadecimal: la codificación de una hltinstrucción, que le dice a la CPU que deje de funcionar.

    Por lo tanto, nuestro programa no hará nada: solo iniciar y detener

    Usamos octal porque \xPOSIX no especifica los números hexadecimales.

    Podríamos obtener esta codificación fácilmente con:

    echo hlt > a.asm
    nasm -f bin a.asm
    hd a
    

    pero la 0xf4codificación también está documentada en el manual de Intel, por supuesto.

  • %509sProducir 509 espacios. Necesario para completar el archivo hasta el byte 510.

  • \125\252en octal == 0x55seguido de 0xaa: bytes mágicos requeridos por el hardware. Deben ser bytes 511 y 512.

    Si no está presente, el hardware no lo tratará como un disco de arranque.

Tenga en cuenta que incluso sin hacer nada, algunos caracteres ya están impresos en la pantalla. Los imprime el firmware y sirven para identificar el sistema.

Ejecutar en hardware real

Los emuladores son divertidos, pero el hardware es el verdadero negocio.

Sin embargo, tenga en cuenta que esto es peligroso, y podría borrar su disco por error: ¡solo haga esto en máquinas viejas que no contienen datos críticos! O incluso mejor, paneles de desarrollo como Raspberry Pi, vea el ejemplo ARM a continuación.

Para una computadora portátil típica, debe hacer algo como:

  • Grabe la imagen en una memoria USB (¡destruirá sus datos!):

    sudo dd if=main.img of=/dev/sdX
    
  • conecte el USB a una computadora

  • encenderlo

  • dile que arranque desde el USB.

    Esto significa hacer que el firmware elija USB antes que el disco duro.

    Si ese no es el comportamiento predeterminado de su máquina, siga presionando Intro, F12, ESC u otras teclas extrañas después del encendido hasta que obtenga un menú de inicio donde puede seleccionar iniciar desde el USB.

    A menudo es posible configurar el orden de búsqueda en esos menús.

Por ejemplo, en mi viejo Lenovo Thinkpad T430, UEFI BIOS 1.16, puedo ver:

Hola Mundo

Ahora que hemos creado un programa mínimo, pasemos a un mundo hola.

La pregunta obvia es: ¿cómo hacer IO? Algunas opciones:

  • pedirle al firmware, por ejemplo, BIOS o UEFI, que lo haga por nosotros
  • VGA: región de memoria especial que se imprime en la pantalla si se escribe en ella. Se puede usar en modo protegido.
  • escriba un controlador y hable directamente al hardware de la pantalla. Esta es la forma "adecuada" de hacerlo: más potente, pero más complejo.
  • puerto serie . Este es un protocolo estandarizado muy simple que envía y recupera caracteres de un terminal host.

    Fuente .

    Desafortunadamente, no está expuesto en la mayoría de las computadoras portátiles modernas, pero es la forma más común de obtener placas de desarrollo, consulte los ejemplos de ARM a continuación.

    Esto es realmente una pena, ya que tales interfaces son realmente útiles para depurar el kernel de Linux, por ejemplo .

  • usar funciones de depuración de chips. ARM llama a ellos semihosting, por ejemplo. En hardware real, requiere soporte adicional de hardware y software, pero en emuladores puede ser una opción conveniente y gratuita. Ejemplo .

Aquí haremos un ejemplo de BIOS, ya que es más simple en x86. Pero tenga en cuenta que no es el método más robusto.

red eléctrica

.code16
    mov $msg, %si
    mov $0x0e, %ah
loop:
    lodsb
    or %al, %al
    jz halt
    int $0x10
    jmp loop
halt:
    hlt
msg:
    .asciz "hello world"

link.ld

SECTIONS
{
    . = 0x7c00;
    .text :
    {
        __start = .;
        *(.text)
        . = 0x1FE;
        SHORT(0xAA55)
    }
}

Ensamblar y vincular con:

gcc -c -g -o main.o main.S
ld --oformat binary -o main.img -T linker.ld main.o

Salir:

ingrese la descripción de la imagen aquí

Probado en: Lenovo Thinkpad T430, UEFI BIOS 1.16. Disco generado en un host Ubuntu 18.04.

Además de las instrucciones de montaje estándar del usuario, tenemos:

  • .code16: le dice a GAS que muestre código de 16 bits

  • cli: deshabilita las interrupciones de software. Esos podrían hacer que el procesador vuelva a funcionar después dehlt

  • int $0x10: hace una llamada de BIOS. Esto es lo que imprime los personajes uno por uno.

Los indicadores de enlace importantes son:

  • --oformat binary: genera el código de ensamblaje binario sin formato, no lo deforma dentro de un archivo ELF, como es el caso de los archivos ejecutables del usuario habitual.

Use C en lugar de ensamblar

Como C se compila para ensamblar, usar C sin la biblioteca estándar es bastante simple, básicamente solo necesitas:

  • Un script de enlace para poner las cosas en la memoria en el lugar correcto
  • banderas que le dicen a GCC que no use la biblioteca estándar
  • un pequeño punto de entrada de ensamblaje que establece el estado C requerido main, en particular:
    • la pila
    • cero BSS

TODO: enlace, así que algún ejemplo x86 en GitHub. Aquí hay un ARM que he creado .

Sin embargo, las cosas se vuelven más divertidas si desea utilizar la biblioteca estándar, ya que no tenemos el kernel de Linux, que implementa gran parte de la funcionalidad de la biblioteca estándar C a través de POSIX .

Algunas posibilidades, sin recurrir a un sistema operativo completo como Linux, incluyen:

  • Newlib

    Ejemplo detallado en: https://electronics.stackexchange.com/questions/223929/c-standard-libraries-on-bare-metal/223931

    En Newlib, debe implementar las llamadas al sistema usted mismo, pero obtiene un sistema muy mínimo y es muy fácil implementarlas.

    Por ejemplo, puede redirigir printfa los sistemas UART o ARM, o implementar exit()con semihosting .

  • sistemas operativos integrados como FreeRTOS y Zephyr .

    Dichos sistemas operativos generalmente le permiten desactivar la programación preventiva, lo que le brinda un control total sobre el tiempo de ejecución del programa.

    Pueden verse como una especie de Newlib pre-implementado.

BRAZO

En ARM, las ideas generales son las mismas. He subido:

Para Raspberry Pi, https://github.com/dwelch67/raspberrypi parece el tutorial más popular disponible en la actualidad.

Algunas diferencias de x86 incluyen:

  • IO se realiza por escrito a las direcciones de magia directa, no hay iny outlas instrucciones.

    Esto se llama memoria asignada IO .

  • para un hardware real, como Raspberry Pi, puede agregar el firmware (BIOS) usted mismo a la imagen del disco.

    Eso es algo bueno, ya que hace que la actualización de ese firmware sea más transparente.

Firmware

En verdad, su sector de arranque no es el primer software que se ejecuta en la CPU del sistema.

Lo que realmente se ejecuta primero es el llamado firmware , que es un software:

  • hecho por los fabricantes de hardware
  • fuente típicamente cerrada pero probablemente basada en C
  • almacenado en memoria de solo lectura y, por lo tanto, más difícil / imposible de modificar sin el consentimiento del proveedor.

Los firmwares bien conocidos incluyen:

  • BIOS : antiguo firmware x86 totalmente presente. SeaBIOS es la implementación de código abierto predeterminada utilizada por QEMU.
  • UEFI : sucesor de BIOS, mejor estandarizado, pero más capaz e increíblemente hinchado.
  • Coreboot : el noble intento de código abierto de arco cruzado

El firmware hace cosas como:

  • haga un bucle sobre cada disco duro, USB, red, etc. hasta que encuentre algo de arranque.

    Cuando ejecutamos QEMU, -hdadice que main.imges un disco duro conectado al hardware, y

    hda es el primero en probarse y se usa.

  • cargue los primeros 512 bytes en la dirección de memoria RAM 0x7c00, coloque el RIP de la CPU allí y déjelo funcionar

  • mostrar cosas como el menú de inicio o las llamadas de impresión del BIOS en la pantalla

El firmware ofrece una funcionalidad similar a la de un sistema operativo, de la cual dependen la mayoría de los sistemas operativos. Por ejemplo, un subconjunto de Python ha sido portado para ejecutarse en BIOS / UEFI: https://www.youtube.com/watch?v=bYQ_lq5dcvM

Se puede argumentar que los firmwares son indistinguibles de los sistemas operativos, y que el firmware es la única programación "verdadera" de metal desnudo que uno puede hacer.

Como dice este desarrollador de CoreOS :

La parte dificil

Cuando enciende una PC, los chips que conforman el conjunto de chips (northbridge, southbridge y SuperIO) aún no se inicializan correctamente. A pesar de que la ROM del BIOS está tan alejada de la CPU como podría estar, la CPU puede acceder a esto, porque tiene que estarlo, de lo contrario la CPU no tendría instrucciones para ejecutar. Esto no significa que la ROM del BIOS esté completamente asignada, generalmente no. Pero solo se asigna lo suficiente para iniciar el proceso de arranque. Cualquier otro dispositivo, solo olvídalo.

Cuando ejecuta Coreboot en QEMU, puede experimentar con las capas superiores de Coreboot y con cargas útiles, pero QEMU ofrece pocas oportunidades para experimentar con el código de inicio de bajo nivel. Por un lado, la RAM solo funciona desde el principio.

Publicar estado inicial del BIOS

Al igual que muchas cosas en el hardware, la estandarización es débil, y una de las cosas en las que no debe confiar es en el estado inicial de los registros cuando su código comienza a ejecutarse después del BIOS.

Hágase un favor y use un código de inicialización como el siguiente: https://stackoverflow.com/a/32509555/895245

Los registros tienen gusto %dsy %estienen efectos secundarios importantes, por lo que debe ponerlos a cero incluso si no los está usando explícitamente.

Tenga en cuenta que algunos emuladores son mejores que el hardware real y le dan un buen estado inicial. Luego, cuando se ejecuta en hardware real, todo se rompe.

GNU GRUB Multiboot

Los sectores de arranque son simples, pero no son muy convenientes:

  • solo puede tener un sistema operativo por disco
  • el código de carga debe ser realmente pequeño y encajar en 512 bytes. Esto podría resolverse con la llamada int 0x13 BIOS .
  • tienes que iniciar mucho tú mismo, como pasar al modo protegido

Es por esas razones que GNU GRUB creó un formato de archivo más conveniente llamado multiboot.

Ejemplo de trabajo mínimo: https://github.com/cirosantilli/x86-bare-metal-examples/tree/d217b180be4220a0b4a453f31275d38e697a99e0/multiboot/hello-world

También lo uso en mi repositorio de ejemplos de GitHub para poder ejecutar fácilmente todos los ejemplos en hardware real sin quemar el USB un millón de veces. En QEMU se ve así:

ingrese la descripción de la imagen aquí

Si prepara su sistema operativo como un archivo de arranque múltiple, GRUB podrá encontrarlo dentro de un sistema de archivos normal.

Esto es lo que hacen la mayoría de las distribuciones, poner las imágenes del sistema operativo debajo /boot.

Los archivos de arranque múltiple son básicamente un archivo ELF con un encabezado especial. GRUB los especifica en: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html

Puede convertir un archivo de arranque múltiple en un disco de arranque con grub-mkrescue.

El Torito

Formato que se puede grabar en CD: https://en.wikipedia.org/wiki/El_Torito_%28CD-ROM_standard%29

También es posible producir una imagen híbrida que funcione en ISO o USB. Esto se puede hacer con grub-mkrescue( ejemplo ), y también lo hace el kernel de Linux al make isoimageusarlo isohybrid.

Recursos

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.