___    __                      _     _ _            _                    
       / _ \  / /       /\            | |   (_) |          | |                 _ 
 __  _| (_) |/ /_      /  \   _ __ ___| |__  _| |_ ___  ___| |_ _   _ _ __ ___(_)
 \ \/ /> _ <| '_ \    / /\ \ | '__/ __| '_ \| | __/ _ \/ __| __| | | | '__/ _ \  
  >  <| (_) | (_) |  / ____ \| | | (__| | | | | ||  __/ (__| |_| |_| | | |  __/_ 
 /_/\_\\___/ \___/  /_/    \_\_|  \___|_| |_|_|\__\___|\___|\__|\__,_|_|  \___(_)
                    _     _ _            _                    __  ___  __        
     /\            | |   (_) |          | |                  /_ |/ _ \/_ |       
    /  \   _ __ ___| |__  _| |_ ___  ___| |_ _   _ _ __ ___   | | | | || |       
   / /\ \ | '__/ __| '_ \| | __/ _ \/ __| __| | | | '__/ _ \  | | | | || |       
  / ____ \| | | (__| | | | | ||  __/ (__| |_| |_| | | |  __/  | | |_| || |       
 /_/    \_\_|  \___|_| |_|_|\__\___|\___|\__|\__,_|_|  \___|  |_|\___/ |_|       
                                                                                 



Welcome to this new series of posts, this time we'll be talking about x86-64 computer 
architecture, specifically, on the firsts posts, I'll give a very very basic 
introduction to computer architecture, how it works, CPU, memory and more, then in 
future posts we'll discuss the hardware support that Intel 64 and IA-32 architectures 
give to Operating Systems to achieve:

    * Memory Management.
    * Memory Addressing.
    * Memory Protection.
    * Separation and protection between Kernel-space and User-space.
    * Interrupts.
    * Hardware I/O.

Besides talking about hardware specific support, we'll explore how the Linux 
Kernel uses those hardware features from x86 processors through kernel debugging, 
analyzing kernel source code and implementing kernel modules that extract 
information to be analized.

By the moment of writing this post, I'm not sure about how many parts will compose 
this series, so this post will be the first out of n posts within this new series.

This first post will be about an introduction to computer architecture, we'll 
discuss the components that a computer system has and how they interact between each 
other (just a general, but complete, description). 

Notice that the content in this post will be just an introduction to all those 
concepts, even when I would try to give you a complete and general overview of the 
architecture of a computer system and how it works, I'm not pretending to touch 
every tiny detail about the subject.

Any way, if you want to go deeper on the concepts discussed in this post, I'll leave 
some useful references and links in the References section.

So, without further ado, let's get started.!



Computer Architecture 101.

A computer system consists of different components and subsystems that work together creating a system able to compute instructions that solve specific tasks. In order to build this kind of system, there are different ways in which you can design it, define its components, its organization and ultimately how everything works within such system. That computer's design is called the Computer Architecture. One of the most well known and implemented computer architecture in today's computer systems is the [Von Neumann Architecture.] There are other computer architectures that are well known and actually implemented by different processors and real applications, such as the [Hardvard Architecture] (https://en.wikipedia.org/wiki/Harvard_architecture). Von Neumann Architecture and Hardvard Architecture have many things in common, but they differ in how some componets interact between each other, how they store and retrieve information depending on the type of information (machine instructions against data) and so on. Any way, since Intel processors implement Von Neumann Architecture, the concepts and theory about computer architecture discussed in this series will relate to Von Neumann Architecture.

System Organization.

Simplifying things, computer systems based on Von Neumann Architecture consist mainly in 3 well defined components: * CPU. * Memory (RAM). * I/O Devices. And then, the CPU have another set of components within it: * Control Unit (CU). * Aritmetic Logic Unit (ALU). * Registers. Von Neumann Machine There are some processors that implement other hardware features such as caches, or even more than one processor within a single chip.

Basic system functionality.

One of the most important features that Von Neumann brought with this architecture is that CPU instructions and data from processes are stored in memory when they are loaded to be executed, then, when a process is executing, the CPU retreives CPU instructions and data as needed. This was not the case in the early's days of computing, when only data could be stored in memory and hardware circuitry had to be modified for each program to be properly executed. Because of this, Von Neumann Architecture systems are also referred as stored-program computers. All computations occur inside the CPU, as mentioned before, it retrieves information (CPU instructions and/or data) from memory and stores information in memory as needed as well. The CPU instructions are retreived and executed one by one, data is stored or retreived as needed, and when the execution of the current instruction is finished, then the CPU fetches the next one and repeats the cycle (this is the normal workflow of execution if we don't consider interrupts, I'll cover software and hardware interrupts in a future post). It might be the case that the current executing process requires access to a hardware device that is connected to the CPU, in that case, the CPU communicates with I/O devices either sending or fetching information to/from them. In this type of computer architecture, to the CPU, dealing with most I/O devices is practically the same as dealing with memory. To the CPU, I/O devices and memory are just external components to which it can interact with by sending or fetching data to/from them. Any way, there are differences in the way CPUs exchange information between memory and I/O devices, and of course, we'll talk about it :D. System Bus Image from Art of Intel x86 Assembly book (see References section) All this components, I/O devices, memory and the CPU, need a way to exchange information between them and the way in which that comunication is implemented is called the System Bus.

The System Bus.

In simple terms, the System Bus is just a set of electrical conexions that exists in the physical circuit (mother board of the computer) and this bus interconnects all the components in the computer system. The System Bus is literally a set of wires that transport electrical signals between computer components. The specific implementation of the System Bus depends totally on the characteristics of the processor that's being used but the function of the bus is always the same, to transport electrical signals between components allowing communication between them. A typical x86 processor uses standard TTL logic levels as voltage for the transmitted signals. A standard TTL logic level zero is represented by a voltage in the range 0.0 - 0.8v, whereas a logic one is represented by a voltage level in the range 2.4 - 5v. The System Bus can be divided in 3 different busses: * Data Bus. * Address Bus. * Control Bus. System Bus These busses have their own porpuse, but remember, all of them have the same essential function, transport electrical signals between components, the meaning of this signals and what information do the busses carry is what defines the specific function of each bus in the system.

The Data Bus.

As it's name suggests, the Data Bus is used to shuffle data between the computer system components. Historically, the size (I mean, how many wires the bus has) has changed between different processors, having size values of: * 8 bits. * 16 bits. * 32 bits. * 64 bits. As you might expect, the newer the processor the bigger the data bus size. Even though all busses have different sizes between processors (data bus, control bus and address bus), the Data Bus size has more impact on the performance of the system than the other ones. Practically, a system with a 16 bit data bus is twice as fast as a system with an 8 bit data bus. And sure, having a 32 bit data bus means that the circuit has 32 physical wires, each wire is equivalent to a bit. That way, the CPU is capable of moving data to/from memory in chunks of the same size of the data bus per memory cycle (by memory cycle, I mean the entire event of storing or fetching data and it's totally different than CPU cycles, so don't confuse them). In a system with an 8 bit data bus, it takes one memory cycle to fetch 8 bits of data, twice for 16 bits and so on. It's important to notice that the size of the data bus does not limit the size of data types that a process (program) can use. You can have 32 bit data types in a program that is running on a system with a data bus of 16 bits, this only means that it will take two memory cycles to fetch the entire 32 bit data. Have you heard someone saying "I have a 32-bit system" or "my laptop is a 64-bit computer"? Well, it turns out that the size of the Data Bus determines what's called the size of the processor. That way, a system with an 8 bit data bus is called an 8 bit processor, same way, a 32 bit processor has a 32 bit data bus. Notice that the data bus is not only used to move data between the CPU and memory, it is used as well for moving data between I/O devices and the CPU. In fact, some I/O devices can appear another section in the accesible memory (remember that to the CPU, most I/O devices are kind of the same as memory). The CPU needs a way to specify from where in memory or from where in an I/O device it wants to fecth data (or store data). The solution to this is provided by the address bus.

The Address Bus.

The CPU uses the address bus to specify the location (memory address) from where it wants to retrieve data (and again, to where store it) either from memory or from an I/O device. So every time the CPU wants to access information in memory or in I/O devices, it just places the corresponding address in the Address Bus. Memory and I/O devices have internal circuitry as well, when the CPU requests information from a specific address, the circuitry from memory and I/O devices recognizes that they contain the address requested by the processor, if they have such address of course, and acts in response (storing or sending data). If they don't recongnize the address, they just ignore it. The amount of wires that the Address Bus has determines the amount of physical addressable memory. That way, if you have an address bus with just one wire, you'd be able to address only two unique addresses, 0 and 1. Firsts x86 processors had an address bus of 20 bits (wires) which allows them to address up to 1,048,576 different locations, which is the same as 1 MegaByte of addressable memory. Modern processors have a 32 bits address bus, which allows them to address up to 4,294,976,296, or 4GB of addressable memory. There exist hardware mechanisms that allow an expansion of addressable memory increasing the address bus from a 32 bit address bus to a 36 bit address bus, allowing the processor to address up to 64GB of memory, but we'll discuss it in a future post :D. Notice that memory and I/O devices share the same address bus! Something important is, the maximum amount of addressable memory is always the same as the address bus size, but the address bus size for I/O devices is always 16 bits long, what happens is that when accessing memory, all the address bus is used to specify the location in memory, but when accessing I/O devices, only the 16 least significat bits of the address bus are used. In consequence the processor is able to address up to 65,536 different I/O locations. If the CPU sees memory and I/O as the same thing, how does the CPU specify that the resquested address belongs to a memory location and not to a I/O device and vice versa? How does the CPU communicates that it wants to store some data at a specific address instead of fetching data from that same address? To solve this issues, the control bus comes into the picture!

The Control Bus.

This is probably the bus that has more differences between different processors, in simple terms, the control bus is used by the CPU to send specific signals to the rest of the components that determines how it wants to communicates. For example, there are 2 dedicated wires in the control bus used to specify if the CPU wants to read data from memory or if it wants to write data to memory. As I said, there are different designs of the control bus, but regardless those differences, there are some signals that are common between processors. There are signals in the control bus that are used to specify when the CPU wants to read or write data, as well as signals used to specify if the CPU wants to access memory or an I/O device. So when the CPU wants to read something from memory, it places the desired address in the address bus, and it places the respective values in the control bus specifying it wants to read instead of writing, and that it want such information from memory and not an I/O device, finally the circuitry from memory recognizes that the CPU is asking for some information from it at an specific location, if such address exists, memory places the data in the data bus and the CPU just reads it, and that's how (in a general description) communication between CPU and memory occurs. Read Memory Images form Art of Intel x86 Assembly book And in the other hand, the control bus places the respective signal on the control bus specifying it wants to write some data in memory. Write Memory Images form Art of Intel x86 Assembly book When the CPU wants information from an I/O device, the process is mostly the same, with the only difference that the CPU places in the control bus a signal specifying that it wants such information from I/O instead of memory. In this scenario, circuitry in the I/O device recognize that the CPU requested information from it, and if it contains the requested address, it responds placing the information located at such address in the data bus. And remember, the address bus for I/O devices is always 16 bits, so the CPU places the requested address in the address bus, but using the least significant bits in the address bus and the remaining bits are just ignored. NOTE: By the moment of writing this post I haven't found that much information about the exact configuration of the control bus signals on different processors, because of that I'm not able to specify the name of the signals, the values and interpretation they have on real processors D:, any way as soon as I get more information I'll update this post :D.

Let's talk about memory.

Just before the end of this post, let's talk about memory. x86 processors supports byte addressable memory, which this means is that the smallest and more basic unit of memory that x86 processors are able to access is a single byte (a byte is equal to 8 bits). You can imagine memory as an array of cells, each cell can store 1 byte, or in other words, each cell is composed of 8 bits, and the exact location of each cell within the array is what is known as the memory address. Read Memory Memory addresses will be always given in hexadecimal numbers, so it's really important that you understand numerical systems and conversions. When dealing with memory values and addresses, you will notice that some places uses the terms word, byte, double word and so on, so let's explain it. The most basic unit of memory (I'm talking about unit of memory itself, not unit of addressable memory by the CPU) is a bit, with it you can represent 2 values, 0 or 1, and those two values could mean whatever you want them to mean, black and white, on or off, up or down, or even 7541 and 500. Then, there are the nibbles, a nibble is a collection of 4 bits and the bit that is at the most right side is called the least significant bit (LSB) in contrast with the most left side bit, which is called the most significant bit (MSB). Then we have a byte, a byte is composed of 8 bits, or 2 nibbles, the nibble that is at the right is called the Low Order nibble and the other one is called the High Order nibble, this because the LO nibble contains the LSB and the HO nibble contains the MSB. Then we have a word, a word consists of 16 bits, or 2 bytes, or 4 nibbles. It also has its LO nibble and HO nibble plus its HO byte and its LO byte. Then there is the double word, a double word contains 32 bits, or 4 bytes, or 8 nibbles, and it has its LO and HO nibbles, bytes and words. Read Memory This terms apply when you are talking about memory values, sizes of data types and other cases, for instance, when reading assembly, you might see an instrucction saying something like: MOV eax, DWORD PTR [ebx] That dword is telling that this assembly instrucction requires to access a value in memory that is a double word value, or a 4 bytes value. Well, this is already a huge post, it might be kind of boring to learn this things, I tried to be as brief as possible but complete and concrete at the same time.

References.

[Von Neumann Architecture] [Hardvard Architecture] [System Bus] [The Art Of Intel x86 Assembly]